├── .gitignore ├── CHANGES ├── CREDITS ├── LICENSE ├── Makefile ├── README ├── cpptcl.cc ├── cpptcl.h ├── details ├── callbacks.h ├── callbacks_cd.h ├── callbacks_v.h ├── constructors.h ├── conversions.h ├── dispatchers.h ├── metahelpers.h ├── methods.h ├── methods_v.h └── trace.h ├── doc ├── callpolicies.html ├── classes.html ├── compiling.html ├── errors.html ├── freefun.html ├── goodies.html ├── images │ ├── bg_hr.png │ ├── blacktocat.png │ ├── icon_download.png │ └── sprite_download.png ├── index.html ├── javascripts │ └── main.js ├── objects.html ├── params.json ├── quickstart.html ├── stylesheets │ ├── pygment_trac.css │ └── stylesheet.css └── trace.html ├── examples ├── Makefile ├── example1.cc ├── example2.cc ├── example3.cc ├── example4.cc ├── example5.cc ├── example6.cc └── example7.cc ├── preproc ├── callbacks.hpp ├── callbacks_cd.hpp ├── callbacks_v.hpp ├── class_definer.hpp └── interp_def.hpp └── test ├── Makefile ├── test1.cc ├── test2.cc ├── test2.tcl ├── test3.cc ├── test4.cc ├── test5.cc ├── test6.cc ├── test7.cc └── test8.cc /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled Object files 2 | *.slo 3 | *.lo 4 | *.o 5 | 6 | # Compiled Dynamic libraries 7 | *.so 8 | 9 | # Compiled Static libraries 10 | *.lai 11 | *.la 12 | *.a 13 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | This file contains the history of changes in the C++/Tcl library. 2 | 3 | (August 24 2012) 4 | Add a new method "tcl_init()" in interpreter to call Tcl_Init() API. 5 | Tcl_Init() will read in System/OS predefined tcl environment, including 6 | the auto_path variable needed for tcl packages. 7 | [According to the request from Kashev Dalmia] 8 | 9 | --- (July 31 2012) 10 | The version 1.1.4.001 differs from 1.1.4 in the following ways: 11 | 12 | - Tracking the global map to ensure the map is the last object to be realeased, 13 | otherwise memory segment error may occur in some systems. 14 | [ Thanks to the crash report from Stephan Effelsberg] 15 | 16 | - Add variables in Makefile to support multiple operating systems. 17 | [Thanks to the suggestions from Stephan Effelsberg] 18 | 19 | - Support a new data type: vector. 20 | 21 | - Support the control of Tcl variables (including set, release and trace). 22 | 23 | - Clean the memory leak in interpreter::clear_definitions(). 24 | 25 | --- (July 9 2012) 26 | The version 1.1.4.001 differs from 1.1.4 in the following ways: 27 | 28 | - Using boost/preprocessor ro reduce template boilerplate. 29 | 30 | - Support variable trace functions. 31 | 32 | - Document updates. 33 | 34 | --- 35 | The version 1.1.4 differs from 1.1.3 in the following ways: 36 | 37 | - New developer. 38 | 39 | - Support a user pass data as the last argument of a function 40 | 41 | - Document updates. 42 | 43 | --- 44 | The version 1.1.3 differs from 1.1.2 in the following ways: 45 | 46 | - A bug in the initialization of interpreter object was fixed. 47 | 48 | --- 49 | The version 1.1.2 differs from 1.1.1 in the following ways: 50 | 51 | - Copyright was updated to cover 2006. 52 | 53 | - Information was added to docs about the usage of the Boost library. 54 | 55 | - Few bug fixes were applied to allow empty parameter lists with variadic 56 | functions. 57 | 58 | --- 59 | The version 1.1.1 differs from 1.1.0 in the following ways: 60 | 61 | - Explicit instantiations of some templates were moved to proper namespace. 62 | 63 | 64 | --- 65 | The version 1.1.0 differs from 1.0.0 in the following ways: 66 | 67 | - CHANGES file was added. 68 | 69 | - LICENSE file was added with clear description of the license terms. 70 | 71 | - Copyright was updated to cover 2005. 72 | 73 | - Small patch was added to make the code compile on g++ 3.2. 74 | 75 | - New assign method was added that accepts Tcl_Obj. 76 | 77 | - Overload of interpreter::eval was added that accepts istream& parameter. 78 | This allows to evaluate the contents of arbitrary stream 79 | (for example, a file). 80 | 81 | - Support for package definitions was added. 82 | 83 | - Support for const class member functions was added. 84 | 85 | - Support for variadic free functions, constructors and class methods 86 | was added. 87 | -------------------------------------------------------------------------------- /CREDITS: -------------------------------------------------------------------------------- 1 | I would like to thank you very much for your contributions: 2 | 3 | --- 4 | Alexey Pakhunov provided patches with various bugfixes and enhancements. 5 | His patches were used in the 1.1.2 release. 6 | 7 | --- 8 | Christoph Pesch provided a small patch for the g++ 3.2 compiler. 9 | 10 | After the 1.1.0 release, Christoph provided also a patch for newer g++ 3.4.3. 11 | (included in 1.1.1) 12 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2011-2012, Wei Song 3 | // Copyright (C) 2004-2006, Maciej Sobczak 4 | // 5 | // Permission to copy, use, modify, sell and distribute this software 6 | // is granted provided this copyright notice appears in all copies. 7 | // This software is provided "as is" without express or implied 8 | // warranty, and with no claim as to its suitability for any purpose. 9 | // 10 | 11 | The above is the shortest license I have found. 12 | I have copied this wording from one of the source files of the Boost library. 13 | 14 | Just to explain the above terms: 15 | 16 | 1. The library is free (like in "freedom"). 17 | 18 | 2. You can use it for any purpose you wish. You can even sell it. 19 | 20 | 3. You can modify the source files. If you do this, please feel free to add 21 | your own copyright notices wherever you want, if you want. 22 | You may also add more restrictive license terms. 23 | You only have to keep the above notice unchanged in all source files. 24 | 25 | 4. You can combine this library or its modified version with other software. 26 | The license claims nothing that would affect the resulting work. 27 | See point 3. if you need to make any modifications. 28 | 29 | 5. You can compile this library or its modified version to the binary form. 30 | The license does not affect the compiled result in any way. 31 | In particular, you do not need to (but you still can) display the above 32 | copyright notice to the final user, and you do not need to (but you still 33 | can) inform the final user that your product was prepared with the help 34 | of this library. 35 | 36 | 6. Do not sue me for my (and your) mistakes and errors. 37 | 38 | As you see, this license is very permissive. 39 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Top level Makefile 2 | # 04/07/2012 Wei Song 3 | # 4 | # 5 | 6 | # global variables 7 | # C++ compiler 8 | export CXX = g++ 9 | 10 | # the Tcl library 11 | OS_NAME := $(shell uname) 12 | # Linux 13 | ifeq ($(OS_NAME), Linux) 14 | TCL_OBJ_LINKFLAG = -ltcl 15 | TCL_SHARED_LINKFLAG = -shared 16 | PIC_FLAG = -fPIC 17 | endif 18 | 19 | # other systems, such as MinGW 20 | ifneq ($(findstring MinGW, $(OS_NAME)),) 21 | TCL_OBJ_LINKFLAG = -ltcl85 -L/usr/local/lib 22 | TCL_SHARED_LINKFLAG = -shared $(shell which tcl85.dll) 23 | PIC_FLAG = 24 | endif 25 | 26 | # export the flags to all sub-directories 27 | export CXXFLAGS = -std=c++0x -Wall -Wextra -g $(PIC_FLAG) 28 | export OBJ_LINKFLAGS = $(TCL_OBJ_LINKFLAG) 29 | export SHARED_LINKFLAGS = $(TCL_SHARED_LINKFLAG) 30 | 31 | # local variables 32 | INCDIRS = -I. 33 | HEADERS = $(wildcard ./*.h) 34 | HEADERS += $(wildcard ./details/*.h) 35 | HEADERS += $(wildcard ./preproc/*.hpp) 36 | 37 | # targets 38 | TESTDIRS = test 39 | EXAMPLEDIRS = examples 40 | 41 | # actions 42 | 43 | all: cpptcl.o 44 | 45 | cpptcl.o : %.o:%.cc $(HEADERS) 46 | $(CXX) $(INCDIRS) $(CXXFLAGS) -c $< -o $@ 47 | 48 | .PHONY: clean $(TESTDIRS) $(EXAMPLEDIRS) 49 | 50 | test: cpptcl.o $(TESTDIRS) 51 | 52 | example: cpptcl.o $(EXAMPLEDIRS) 53 | 54 | $(TESTDIRS): 55 | $(MAKE) -C $@ 56 | 57 | $(EXAMPLEDIRS): 58 | $(MAKE) -C $@ 59 | 60 | clean: 61 | -rm *.o 62 | -for d in $(EXAMPLEDIRS); do $(MAKE) -C $$d clean; done 63 | -for d in $(TESTDIRS); do $(MAKE) -C $$d clean; done 64 | 65 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | C++/Tcl - a C++ library for interoperability between C++ and Tcl. 2 | 3 | Version 1.1.4.002 July 31, 2012 4 | 5 | Copyright (C) 2012, Wei Song 6 | Copyright (C) 2004-2006, Maciej Sobczak (the original author) 7 | 8 | --- 9 | 10 | You should see the following directories here: 11 | 12 | - doc - contains a short documentation for the library 13 | or see http://wsong83.github.com/cpptcl 14 | - examples - some simple examples to show C++/Tcl basics 15 | - test - tests used for development - use them for regression testing 16 | if you want to modify the library 17 | - details - some additional code used by the library (not for client use) 18 | 19 | In addition, the following files may be of interest to you: 20 | 21 | - README - this file 22 | - LICENSE - explanation of the license terms 23 | - CHANGES - the history of changes 24 | 25 | 26 | The C++/Tcl itself consists of these files: 27 | - cpptcl.h - to be included in your own files 28 | - cpptcl.cc - to be compiled and linked with your code 29 | 30 | 31 | In order to compile the tests and the examples you may need to change the 32 | compiler options to fit your particular environment (different paths to the 33 | Tcl headers and libs, another compiler, etc.) 34 | 35 | 36 | Anyway - have fun! :-) 37 | -------------------------------------------------------------------------------- /cpptcl.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2012, Wei Song 2 | // Copyright (C) 2004-2006, Maciej Sobczak 3 | // 4 | // Permission to copy, use, modify, sell and distribute this software 5 | // is granted provided this copyright notice appears in all copies. 6 | // This software is provided "as is" without express or implied 7 | // warranty, and with no claim as to its suitability for any purpose. 8 | // 9 | 10 | #ifndef CPPTCL_INCLUDED 11 | #define CPPTCL_INCLUDED 12 | 13 | extern "C" { 14 | #include 15 | } 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | namespace Tcl 30 | { 31 | 32 | // exception class used for reporting all Tcl errors 33 | 34 | class tcl_error : public std::runtime_error 35 | { 36 | public: 37 | explicit tcl_error(std::string const &msg) 38 | : std::runtime_error(msg) {} 39 | explicit tcl_error(Tcl_Interp *interp) 40 | : std::runtime_error(Tcl_GetString(Tcl_GetObjResult(interp))) {} 41 | }; 42 | 43 | // call policies 44 | 45 | struct policies 46 | { 47 | policies() : variadic_(false) {} 48 | 49 | policies & factory(std::string const &name); 50 | 51 | // note: this is additive 52 | policies & sink(int index); 53 | 54 | policies & variadic(); 55 | 56 | std::string factory_; 57 | std::vector sinks_; 58 | bool variadic_; 59 | }; 60 | 61 | // syntax short-cuts 62 | policies factory(std::string const &name); 63 | policies sink(int index); 64 | policies variadic(); 65 | 66 | 67 | class interpreter; 68 | class object; 69 | class tcl_name_database; 70 | 71 | namespace details 72 | { 73 | 74 | // wrapper for the evaluation result 75 | class result 76 | { 77 | public: 78 | result(Tcl_Interp *interp); 79 | 80 | operator bool() const; 81 | operator double() const; 82 | operator int() const; 83 | operator long() const; 84 | operator long long() const; 85 | operator std::string() const; 86 | operator object() const; 87 | 88 | private: 89 | Tcl_Interp *interp_; 90 | }; 91 | 92 | // helper functions used to set the result value 93 | 94 | void set_result(Tcl_Interp *interp, bool b); 95 | void set_result(Tcl_Interp *interp, int i); 96 | void set_result(Tcl_Interp *interp, long i); 97 | void set_result(Tcl_Interp *interp, long long i); 98 | void set_result(Tcl_Interp *interp, double d); 99 | void set_result(Tcl_Interp *interp, std::string const &s); 100 | void set_result(Tcl_Interp *interp, void *p); 101 | void set_result(Tcl_Interp *interp, object const &o); 102 | 103 | // helper functor for converting Tcl objects to the given type 104 | #include "details/conversions.h" 105 | 106 | // dispatchers able to capture (or ignore) the result 107 | #include "details/dispatchers.h" 108 | 109 | // helper for checking for required number of parameters 110 | // (throws tcl_error when not met) 111 | void check_params_no(int objc, int required); 112 | 113 | // helper for gathering optional params in variadic functions 114 | object get_var_params(Tcl_Interp *interp, 115 | int objc, Tcl_Obj * CONST objv[], 116 | int from, policies const &pol); 117 | 118 | // the callback_base is used to store callback handlers in a polynorphic map 119 | class callback_base 120 | { 121 | public: 122 | virtual ~callback_base() {} 123 | 124 | virtual void invoke(Tcl_Interp *interp, 125 | int objc, Tcl_Obj * CONST objv[], 126 | policies const &pol, ClientData) = 0; 127 | }; 128 | 129 | 130 | // base class for object command handlers 131 | // and for class handlers 132 | class object_cmd_base 133 | { 134 | public: 135 | // destructor not needed, but exists to shut up the compiler warnings 136 | virtual ~object_cmd_base() {} 137 | 138 | virtual void invoke(void *p, Tcl_Interp *interp, 139 | int objc, Tcl_Obj * CONST objv[], 140 | policies const &pol) = 0; 141 | }; 142 | 143 | // base class for all class handlers, still abstract 144 | class class_handler_base : public object_cmd_base 145 | { 146 | public: 147 | typedef std::map policies_map_type; 148 | 149 | class_handler_base(); 150 | 151 | void register_method(std::string const &name, 152 | boost::shared_ptr ocb, policies const &p); 153 | 154 | policies & get_policies(std::string const &name); 155 | 156 | protected: 157 | typedef std::map< 158 | std::string, 159 | boost::shared_ptr 160 | > method_map_type; 161 | 162 | // a map of methods for the given class 163 | method_map_type methods_; 164 | 165 | policies_map_type policies_; 166 | }; 167 | 168 | // class handler - responsible for executing class methods 169 | template 170 | class class_handler : public class_handler_base 171 | { 172 | public: 173 | virtual void invoke(void *pv, Tcl_Interp *interp, 174 | int objc, Tcl_Obj * CONST objv[], policies const &pol) 175 | { 176 | C * p = static_cast(pv); 177 | 178 | if (objc < 2) 179 | { 180 | throw tcl_error("Too few arguments."); 181 | } 182 | 183 | std::string methodName(Tcl_GetString(objv[1])); 184 | 185 | if (methodName == "-delete") 186 | { 187 | Tcl_DeleteCommand(interp, Tcl_GetString(objv[0])); 188 | delete p; 189 | return; 190 | } 191 | 192 | // dispatch on the method name 193 | 194 | method_map_type::iterator it = methods_.find(methodName); 195 | if (it == methods_.end()) 196 | { 197 | throw tcl_error("Method " + methodName + " not found."); 198 | } 199 | 200 | it->second->invoke(pv, interp, objc, objv, pol); 201 | } 202 | }; 203 | 204 | 205 | // factory functions for creating class objects 206 | #include "details/constructors.h" 207 | 208 | // actual callback envelopes 209 | #include "details/callbacks.h" 210 | #include "details/callbacks_cd.h" 211 | 212 | // trace functions 213 | #include "details/trace.h" 214 | 215 | // actual method envelopes 216 | #include "details/methods.h" 217 | 218 | // helper meta function for figuring appropriate constructor callback 219 | #include "details/metahelpers.h" 220 | 221 | 222 | // this class is used to provide the "def" interface for defining 223 | // class member functions 224 | 225 | template 226 | class class_definer 227 | { 228 | public: 229 | class_definer(boost::shared_ptr > ch) : ch_(ch) {} 230 | 231 | #define BOOST_PP_ITERATION_LIMITS (0, 9) 232 | #define BOOST_PP_FILENAME_1 "preproc/class_definer.hpp" 233 | #include BOOST_PP_ITERATE() 234 | #undef BOOST_PP_ITERATION_LIMITS 235 | #undef BOOST_PP_FILENAME_1 236 | 237 | private: 238 | boost::shared_ptr > ch_; 239 | }; 240 | 241 | } // namespace details 242 | 243 | 244 | // init type for defining class constructors 245 | template 248 | class init {}; 249 | 250 | // no_init type and object - to define classes without constructors 251 | namespace details 252 | { 253 | struct no_init_type {}; 254 | } // namespace details 255 | extern details::no_init_type no_init; 256 | 257 | 258 | // interpreter wrapper 259 | class interpreter 260 | { 261 | public: 262 | interpreter(); 263 | interpreter(Tcl_Interp *, bool owner = true); 264 | virtual ~interpreter(); 265 | 266 | void make_safe(); 267 | void tcl_init(); // call Tcl_Init() to set up OS variables 268 | 269 | Tcl_Interp * get() const { return interp_; } 270 | 271 | // free function definitions 272 | 273 | #define BOOST_PP_ITERATION_LIMITS (0, 9) 274 | #define BOOST_PP_FILENAME_1 "preproc/interp_def.hpp" 275 | #include BOOST_PP_ITERATE() 276 | #undef BOOST_PP_ITERATION_LIMITS 277 | #undef BOOST_PP_FILENAME_1 278 | 279 | // class definitions 280 | 281 | template 282 | details::class_definer class_(std::string const &name) 283 | { 284 | boost::shared_ptr > ch( 285 | new details::class_handler()); 286 | 287 | add_class(name, ch); 288 | 289 | add_constructor(name, ch, 290 | boost::shared_ptr( 291 | new details::callback0(&details::construct< 292 | C, void, void, void, void, void, void, void, 293 | void, void>::doit))); 294 | 295 | return details::class_definer(ch); 296 | } 297 | 298 | template 301 | details::class_definer class_(std::string const &name, 302 | init const &, 303 | policies const &p = policies()) 304 | { 305 | typedef typename details::get_callback_type_for_construct< 306 | C, T1, T2, T3, T4, T5, T6, T7, T8, T9>::type 307 | callback_type; 308 | 309 | boost::shared_ptr > ch( 310 | new details::class_handler()); 311 | 312 | add_class(name, ch); 313 | 314 | add_constructor(name, ch, 315 | boost::shared_ptr( 316 | new callback_type(&details::construct< 317 | C, T1, T2, T3, T4, T5, T6, T7, T8, T9>::doit)), p); 318 | 319 | return details::class_definer(ch); 320 | } 321 | 322 | template 323 | details::class_definer class_( 324 | std::string const &name, details::no_init_type const &) 325 | { 326 | boost::shared_ptr > ch( 327 | new details::class_handler()); 328 | 329 | add_class(name, ch); 330 | 331 | return details::class_definer(ch); 332 | } 333 | 334 | // free script evaluation 335 | details::result eval(std::string const &script); 336 | details::result eval(std::istream &s); 337 | 338 | details::result eval(object const &o); 339 | 340 | // the InputIterator should give object& or Tcl_Obj* when dereferenced 341 | template 342 | details::result eval(InputIterator first, InputIterator last); 343 | 344 | // create alias from the *this interpreter to the target interpreter 345 | void create_alias(std::string const &cmd, 346 | interpreter &targetInterp, std::string const &targetCmd); 347 | 348 | // register a package info (useful when defining packages) 349 | void pkg_provide(std::string const &name, std::string const &version); 350 | 351 | // helper for cleaning up callbacks in non-managed interpreters 352 | static void clear_definitions(Tcl_Interp *); 353 | 354 | // create a trace to a variable 355 | // a read trace using variable name 356 | template 357 | void def_read_trace(const std::string& VarName, // variable name 358 | const std::string& FunName, // function name 359 | VT (*proc)(VT const &, CDT *), // callback function 360 | CDT *cData = NULL) { // the data passed to the callback function 361 | add_trace(VarName, NULL, FunName, 362 | boost::shared_ptr 363 | (new details::trace(proc)), 364 | cData, TCL_TRACE_READS); 365 | } 366 | 367 | // a read trace using array name and its index 368 | template 369 | void def_read_trace(const std::string& VarName, // variable name 370 | unsigned int index, // the index of a array element 371 | const std::string& FunName, // function name 372 | VT (*proc)(VT const &, CDT *), // callback 373 | CDT *cData = NULL) { // the data passed to the callback function 374 | add_trace(VarName, &index, FunName, 375 | boost::shared_ptr 376 | (new details::trace(proc)), 377 | cData, TCL_TRACE_READS); 378 | } 379 | 380 | // a read trace using variable name 381 | template 382 | void def_write_trace(const std::string& VarName, // variable name 383 | const std::string& FunName, // function name 384 | VT (*proc)(VT const &, CDT *), // callback function 385 | CDT *cData = NULL) { // the data passed to the callback function 386 | add_trace(VarName, NULL, FunName, 387 | boost::shared_ptr 388 | (new details::trace(proc)), 389 | cData, TCL_TRACE_WRITES); 390 | } 391 | 392 | // a read trace using array name and its index 393 | template 394 | void def_write_trace(const std::string& VarName, // variable name 395 | unsigned int index, // the index of a array element 396 | const std::string& FunName, // function name 397 | VT (*proc)(VT const &, CDT *), // callback 398 | CDT *cData = NULL) { // the data passed to the callback function 399 | add_trace(VarName, &index, FunName, 400 | boost::shared_ptr 401 | (new details::trace(proc)), 402 | cData, TCL_TRACE_WRITES); 403 | } 404 | 405 | // delete a read trace using variable name 406 | void undef_read_trace(const std::string& VarName, // variable name 407 | const std::string& FunName = "") { 408 | remove_trace(VarName, NULL, FunName, TCL_TRACE_READS); 409 | } 410 | 411 | // delete a read trace using array name and its index 412 | void undef_read_trace(const std::string& VarName, // variable name 413 | unsigned int index, // the index of a array element 414 | const std::string& FunName = "") { 415 | remove_trace(VarName, &index, FunName, TCL_TRACE_READS); 416 | } 417 | 418 | // delete a write trace using variable name 419 | void undef_write_trace(const std::string& VarName, // variable name 420 | const std::string& FunName = "") { 421 | remove_trace(VarName, NULL, FunName, TCL_TRACE_WRITES); 422 | } 423 | 424 | // delete a write trace using array name and its index 425 | void undef_write_trace(const std::string& VarName, // variable name 426 | unsigned int index, // the index of a array element 427 | const std::string& FunName = "") { 428 | remove_trace(VarName, &index, FunName, TCL_TRACE_WRITES); 429 | } 430 | 431 | // delete all traces using variable name 432 | void undef_all_trace(const std::string& VarName) { // variable name 433 | remove_trace(VarName, NULL, "", TCL_TRACE_WRITES|TCL_TRACE_READS); 434 | } 435 | 436 | // delete all traces using array name and its index 437 | void undef_all_trace(const std::string& VarName, // variable name 438 | unsigned int index) { // the index of a array element 439 | remove_trace(VarName, &index, "", TCL_TRACE_WRITES|TCL_TRACE_READS); 440 | } 441 | 442 | // add Tcl variables 443 | template 444 | void set_variable(const std::string& VarName, VT const & var) { 445 | Tcl_SetVar2Ex(interp_, VarName.c_str(), 446 | NULL, 447 | details::tcl_cast::to(interp_, var), 0); 448 | } 449 | 450 | template 451 | void set_variable(const std::string& VarName, unsigned int index, VT const & var) { 452 | Tcl_SetVar2Ex(interp_, VarName.c_str(), 453 | boost::lexical_cast(index).c_str(), 454 | details::tcl_cast::to(interp_, var), 0); 455 | } 456 | 457 | // remove Tcl variables 458 | void remove_variable(const std::string& VarName) { 459 | Tcl_UnsetVar(interp_, VarName.c_str(), 0); 460 | } 461 | 462 | void remove_variable(const std::string& VarName, unsigned int index) { 463 | Tcl_UnsetVar2(interp_, VarName.c_str(), 464 | boost::lexical_cast(index).c_str(), 0); 465 | } 466 | 467 | // read Tcl variables 468 | template 469 | VT read_variable(const std::string& VarName) { 470 | return 471 | details::tcl_cast:: 472 | from(interp_, Tcl_GetVar2Ex(interp_, VarName.c_str(), 473 | NULL, 0)); 474 | } 475 | 476 | template 477 | VT read_variable(const std::string& VarName, unsigned int index) { 478 | return 479 | details::tcl_cast:: 480 | from(interp_, Tcl_GetVar2Ex(interp_, VarName.c_str(), 481 | boost::lexical_cast(index).c_str(), 0)); 482 | } 483 | 484 | 485 | private: 486 | 487 | // copy not supported 488 | interpreter(const interpreter &); 489 | void operator=(const interpreter &); 490 | 491 | void add_function(std::string const &name, 492 | boost::shared_ptr cb, 493 | policies const &p = policies(), ClientData cData = NULL); 494 | 495 | void add_trace(const std::string& VarName, unsigned int *index, 496 | const std::string& FunName, 497 | boost::shared_ptr proc, 498 | void * cData, int flag); 499 | 500 | void remove_trace(const std::string& VarName, unsigned int *index, 501 | const std::string& FunName, int flag); 502 | 503 | void add_class(std::string const &name, 504 | boost::shared_ptr chb); 505 | 506 | void add_constructor(std::string const &name, 507 | boost::shared_ptr chb, 508 | boost::shared_ptr cb, 509 | policies const &p = policies()); 510 | 511 | Tcl_Interp *interp_; 512 | bool owner_; 513 | // ensure the global database is not release before the release of all interpreters 514 | boost::shared_ptr db_; 515 | }; 516 | 517 | 518 | // object wrapper 519 | class object 520 | { 521 | public: 522 | 523 | // constructors 524 | 525 | object(); 526 | 527 | explicit object(bool b); 528 | object(char const *buf, size_t size); // byte array 529 | explicit object(double b); 530 | explicit object(int i); 531 | 532 | // list creation 533 | // the InputIterator should give object& or Tcl_Obj* when dereferenced 534 | template 535 | object(InputIterator first, InputIterator last) 536 | : interp_(0) 537 | { 538 | std::vector v; 539 | fill_vector(v, first, last); 540 | obj_ = Tcl_NewListObj(static_cast(v.size()), 541 | v.empty() ? NULL : &v[0]); 542 | Tcl_IncrRefCount(obj_); 543 | } 544 | 545 | explicit object(long i); 546 | explicit object(long long i); 547 | explicit object(char const *s); // string construction 548 | explicit object(std::string const &s); // string construction 549 | explicit object(std::vector const &s); 550 | explicit object(Tcl_Obj *o, bool shared = false); 551 | 552 | object(object const &other, bool shared = false); 553 | ~object(); 554 | 555 | // assignment 556 | 557 | object & assign(bool b); 558 | object & resize(size_t size); // byte array resize 559 | object & assign(char const *buf, size_t size); // byte array assignment 560 | object & assign(double d); 561 | object & assign(int i); 562 | 563 | // list assignment 564 | // the InputIterator should give Tcl_Obj* or object& when dereferenced 565 | template 566 | object & assign(InputIterator first, InputIterator last) 567 | { 568 | std::vector v; 569 | fill_vector(v, first, last); 570 | Tcl_SetListObj(obj_, static_cast(v.size()), 571 | v.empty() ? NULL : &v[0]); 572 | return *this; 573 | } 574 | 575 | object & assign(long i); 576 | object & assign(long long i); 577 | object & assign(char const *s); // string assignment 578 | object & assign(std::string const &s); // string assignment 579 | object & assign(std::vector const &s); 580 | object & assign(object const &o); 581 | object & assign(Tcl_Obj *o); 582 | 583 | object & operator=(bool b) { return assign(b); } 584 | object & operator=(double d) { return assign(d); } 585 | object & operator=(int i) { return assign(i); } 586 | object & operator=(long i) { return assign(i); } 587 | object & operator=(long long i) { return assign(i); } 588 | object & operator=(char const *s) { return assign(s); } 589 | object & operator=(std::string const &s) { return assign(s); } 590 | object & operator=(std::vector const &s) { return assign(s); } 591 | 592 | object & operator=(object const &o) { return assign(o); } 593 | object & swap(object &other); 594 | 595 | // (logically) non-modifying members 596 | 597 | template 598 | T get(interpreter &i) const; 599 | 600 | // specialization for string without interpreter 601 | std::string get_string() const; 602 | 603 | char const * get() const; // string get 604 | char const * get(size_t &size) const; // byte array get 605 | 606 | size_t length(interpreter &i) const; // returns list length 607 | object at(interpreter &i, size_t index) const; 608 | 609 | Tcl_Obj * get_object() const { return obj_; } 610 | 611 | // modifying members 612 | 613 | object & append(interpreter &i, object const &o); 614 | object & append_list(interpreter &i, object const &o); 615 | 616 | // list replace 617 | // the InputIterator should give Tcl_Obj* or object& when dereferenced 618 | template 619 | object & replace(interpreter &i, size_t index, size_t count, 620 | InputIterator first, InputIterator last) 621 | { 622 | std::vector v; 623 | fill_vector(v, first, last); 624 | int res = Tcl_ListObjReplace(i.get(), obj_, 625 | static_cast(index), static_cast(count), 626 | static_cast(v.size()), v.empty() ? NULL : &v[0]); 627 | if (res != TCL_OK) 628 | { 629 | throw tcl_error(i.get()); 630 | } 631 | 632 | return *this; 633 | } 634 | 635 | object & replace(interpreter &i, size_t index, size_t count, 636 | object const &o); 637 | object & replace_list(interpreter &i, size_t index, size_t count, 638 | object const &o); 639 | 640 | // helper functions for piggy-backing interpreter info 641 | void set_interp(Tcl_Interp *interp); 642 | Tcl_Interp * get_interp() const; 643 | 644 | // helper function, also used from interpreter::eval 645 | template 646 | static void fill_vector(std::vector &v, 647 | InputIterator first, InputIterator last) 648 | { 649 | for (; first != last; ++first) 650 | { 651 | object o(*first, true); 652 | v.push_back(o.obj_); 653 | } 654 | } 655 | 656 | private: 657 | 658 | // helper function used from copy constructors 659 | void init(Tcl_Obj *o, bool shared); 660 | 661 | Tcl_Obj *obj_; 662 | Tcl_Interp *interp_; 663 | }; 664 | 665 | // available specializations for object::get 666 | template <> bool object::get(interpreter &i) const; 667 | template <> double object::get(interpreter &i) const; 668 | template <> int object::get(interpreter &i) const; 669 | template <> long object::get(interpreter &i) const; 670 | template <> long long object::get(interpreter &i) const; 671 | template <> char const * object::get(interpreter &i) const; 672 | template <> std::string object::get(interpreter &i) const; 673 | template <> 674 | std::vector object::get >(interpreter &i) const; 675 | template <> 676 | std::vector object::get >(interpreter &i) const; 677 | 678 | // the InputIterator should give object& or Tcl_Obj* when dereferenced 679 | template 680 | details::result interpreter::eval(InputIterator first, InputIterator last) 681 | { 682 | std::vector v; 683 | object::fill_vector(v, first, last); 684 | int cc = Tcl_EvalObjv(interp_, 685 | static_cast(v.size()), v.empty() ? NULL : &v[0], 0); 686 | if (cc != TCL_OK) 687 | { 688 | throw tcl_error(interp_); 689 | } 690 | 691 | return details::result(interp_); 692 | } 693 | 694 | namespace details 695 | { 696 | 697 | // additional callback envelopes for variadic functions 698 | #include "details/callbacks_v.h" 699 | 700 | // additional method envelopes for variadic methods 701 | #include "details/methods_v.h" 702 | 703 | } // namespace details 704 | 705 | } // namespace Tcl 706 | 707 | 708 | // macro for defining loadable module entry point 709 | // - used for extending Tcl interpreter 710 | 711 | #define CPPTCL_MODULE(name, i) void name##_cpptcl_Init(Tcl::interpreter &i); \ 712 | extern "C" int name##_Init(Tcl_Interp *interp) \ 713 | { \ 714 | Tcl::interpreter i(interp, false); \ 715 | name##_cpptcl_Init(i); \ 716 | return TCL_OK; \ 717 | } \ 718 | void name##_cpptcl_Init(Tcl::interpreter &i) 719 | 720 | 721 | #endif // CPPTCL_INCLUDED 722 | 723 | // Local Variables: 724 | // mode: c++ 725 | // End: 726 | -------------------------------------------------------------------------------- /details/callbacks.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2012, Wei Song 2 | // Copyright (C) 2004-2006, Maciej Sobczak 3 | // 4 | // Permission to copy, use, modify, sell and distribute this software 5 | // is granted provided this copyright notice appears in all copies. 6 | // This software is provided "as is" without express or implied 7 | // warranty, and with no claim as to its suitability for any purpose. 8 | // 9 | 10 | // Note: this file is not supposed to be a stand-alone header 11 | 12 | template 13 | class callback0 : public callback_base 14 | { 15 | typedef R (*functor_type)(); 16 | 17 | public: 18 | callback0(functor_type f) : f_(f) {} 19 | 20 | virtual void invoke(Tcl_Interp *interp, 21 | int, Tcl_Obj * CONST [], 22 | policies const &, ClientData) 23 | { 24 | dispatch::do_dispatch(interp, f_); 25 | } 26 | 27 | private: 28 | functor_type f_; 29 | }; 30 | 31 | #define BOOST_PP_ITERATION_LIMITS (1, 9) 32 | #define BOOST_PP_FILENAME_1 "preproc/callbacks.hpp" 33 | #include BOOST_PP_ITERATE() 34 | #undef BOOST_PP_ITERATION_LIMITS 35 | #undef BOOST_PP_FILENAME_1 36 | -------------------------------------------------------------------------------- /details/callbacks_cd.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2012, Wei Song 2 | // Copyright (C) 2004-2006, Maciej Sobczak 3 | // 4 | // Permission to copy, use, modify, sell and distribute this software 5 | // is granted provided this copyright notice appears in all copies. 6 | // This software is provided "as is" without express or implied 7 | // warranty, and with no claim as to its suitability for any purpose. 8 | // 9 | 10 | // Note: this file is not supposed to be a stand-alone header 11 | 12 | template 13 | class callback1_cd : public callback_base 14 | { 15 | typedef R (*functor_type)(T1 *); 16 | 17 | public: 18 | callback1_cd(functor_type f) : f_(f) {} 19 | 20 | virtual void invoke(Tcl_Interp *interp, 21 | int objc, Tcl_Obj * CONST [], 22 | policies const &, ClientData cd) 23 | { 24 | check_params_no(objc, 1); 25 | 26 | dispatch:: 27 | template do_dispatch(interp, f_, 28 | static_cast(cd)); 29 | } 30 | 31 | private: 32 | functor_type f_; 33 | }; 34 | 35 | template 36 | class callback2_cd : public callback_base 37 | { 38 | typedef R (*functor_type)(T1, T2 *); 39 | 40 | public: 41 | callback2_cd(functor_type f) : f_(f) {} 42 | 43 | virtual void invoke(Tcl_Interp *interp, 44 | int objc, Tcl_Obj * CONST objv[], 45 | policies const &, ClientData cd) 46 | { 47 | check_params_no(objc, 2); 48 | 49 | dispatch:: 50 | template do_dispatch(interp, f_, 51 | tcl_cast::from(interp, objv[1]), 52 | static_cast(cd)); 53 | } 54 | 55 | private: 56 | functor_type f_; 57 | }; 58 | 59 | template 60 | class callback2_cd : public callback_base 61 | { 62 | typedef object const & T1; 63 | typedef R (*functor_type)(T1, T2 *); 64 | enum { var_start = 1 }; 65 | 66 | public: 67 | callback2_cd(functor_type f) : f_(f) {} 68 | 69 | virtual void invoke(Tcl_Interp *interp, 70 | int objc, Tcl_Obj * CONST objv[], 71 | policies const &pol, ClientData cd) 72 | { 73 | object t1 = get_var_params(interp, objc, objv, var_start, pol); 74 | dispatch:: 75 | template do_dispatch(interp, f_, 76 | t1, 77 | static_cast(cd)); 78 | } 79 | 80 | private: 81 | functor_type f_; 82 | }; 83 | 84 | #define BOOST_PP_ITERATION_LIMITS (3, 10) 85 | #define BOOST_PP_FILENAME_1 "preproc/callbacks_cd.hpp" 86 | #include BOOST_PP_ITERATE() 87 | #undef BOOST_PP_ITERATION_LIMITS 88 | #undef BOOST_PP_FILENAME_1 89 | 90 | -------------------------------------------------------------------------------- /details/callbacks_v.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2012, Wei Song 2 | // Copyright (C) 2004-2006, Maciej Sobczak 3 | // 4 | // Permission to copy, use, modify, sell and distribute this software 5 | // is granted provided this copyright notice appears in all copies. 6 | // This software is provided "as is" without express or implied 7 | // warranty, and with no claim as to its suitability for any purpose. 8 | // 9 | 10 | // Note: this file is not supposed to be a stand-alone header 11 | 12 | template 13 | class callback1 : public callback_base 14 | { 15 | typedef object const & T1; 16 | typedef R (*functor_type)(T1); 17 | enum { var_start = 1 }; 18 | 19 | public: 20 | callback1(functor_type f) : f_(f) {} 21 | 22 | virtual void invoke(Tcl_Interp *interp, 23 | int objc, Tcl_Obj * CONST objv[], 24 | policies const &pol, ClientData) 25 | { 26 | object t1 = get_var_params(interp, objc, objv, var_start, pol); 27 | dispatch::template do_dispatch(interp, f_, 28 | t1); 29 | } 30 | 31 | private: 32 | functor_type f_; 33 | }; 34 | 35 | #define BOOST_PP_ITERATION_LIMITS (2, 9) 36 | #define BOOST_PP_FILENAME_1 "preproc/callbacks_v.hpp" 37 | #include BOOST_PP_ITERATE() 38 | #undef BOOST_PP_ITERATION_LIMITS 39 | #undef BOOST_PP_FILENAME_1 40 | -------------------------------------------------------------------------------- /details/constructors.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2004-2006, Maciej Sobczak 3 | // 4 | // Permission to copy, use, modify, sell and distribute this software 5 | // is granted provided this copyright notice appears in all copies. 6 | // This software is provided "as is" without express or implied 7 | // warranty, and with no claim as to its suitability for any purpose. 8 | // 9 | 10 | // Note: this file is not supposed to be a stand-alone header 11 | 12 | 13 | template 15 | struct construct 16 | { 17 | static C * doit(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, 18 | T8 t8, T9 t9) 19 | { return new C(t1, t2, t3, t4, t5, t6, t7, t8, t9); } 20 | }; 21 | 22 | template 24 | struct construct 25 | { 26 | static C * doit(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) 27 | { return new C(t1, t2, t3, t4, t5, t6, t7, t8); } 28 | }; 29 | 30 | template 32 | struct construct 33 | { 34 | static C * doit(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) 35 | { return new C(t1, t2, t3, t4, t5, t6, t7); } 36 | }; 37 | 38 | template 40 | struct construct 41 | { 42 | static C * doit(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) 43 | { return new C(t1, t2, t3, t4, t5, t6); } 44 | }; 45 | 46 | template 48 | struct construct 49 | { 50 | static C * doit(T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) 51 | { return new C(t1, t2, t3, t4, t5); } 52 | }; 53 | 54 | template 55 | struct construct 56 | { 57 | static C * doit(T1 t1, T2 t2, T3 t3, T4 t4) 58 | { return new C(t1, t2, t3, t4); } 59 | }; 60 | 61 | template 62 | struct construct 63 | { 64 | static C * doit(T1 t1, T2 t2, T3 t3) 65 | { return new C(t1, t2, t3); } 66 | }; 67 | 68 | template 69 | struct construct 70 | { 71 | static C * doit(T1 t1, T2 t2) 72 | { return new C(t1, t2); } 73 | }; 74 | 75 | template 76 | struct construct 77 | { 78 | static C * doit(T1 t1) 79 | { return new C(t1); } 80 | }; 81 | 82 | template 83 | struct construct 85 | { 86 | static C * doit() 87 | { return new C(); } 88 | }; 89 | -------------------------------------------------------------------------------- /details/conversions.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2012, Wei Song 2 | // Copyright (C) 2004-2006, Maciej Sobczak 3 | // 4 | // Permission to copy, use, modify, sell and distribute this software 5 | // is granted provided this copyright notice appears in all copies. 6 | // This software is provided "as is" without express or implied 7 | // warranty, and with no claim as to its suitability for any purpose. 8 | // 9 | 10 | // Note: this file is not supposed to be a stand-alone header 11 | 12 | 13 | // helper functor for converting Tcl objects to the given type 14 | // (it is a struct instead of function, 15 | // because I need to partially specialize it) 16 | 17 | template 18 | struct tcl_cast; 19 | 20 | template 21 | struct tcl_cast 22 | { 23 | static T * from(Tcl_Interp *, Tcl_Obj *obj) 24 | { 25 | std::string s(Tcl_GetString(obj)); 26 | if (s.size() == 0) 27 | { 28 | throw tcl_error("Expected pointer value, got empty string."); 29 | } 30 | 31 | if (s[0] != 'p') 32 | { 33 | throw tcl_error("Expected pointer value."); 34 | } 35 | 36 | std::istringstream ss(s); 37 | char dummy; 38 | void *p; 39 | ss >> dummy >> p; 40 | 41 | return static_cast(p); 42 | } 43 | 44 | static Tcl_Obj * to(Tcl_Interp *, T* v) { 45 | std::ostringstream ss; 46 | ss << 'p' << static_cast(v); 47 | std::string s(ss.str()); 48 | return Tcl_NewStringObj(s.data(), static_cast(s.size())); 49 | } 50 | 51 | }; 52 | 53 | // the following partial specialization is to strip reference 54 | // (it returns a temporary object of the underlying type, which 55 | // can be bound to the const-ref parameter of the actual function) 56 | 57 | template 58 | struct tcl_cast 59 | { 60 | static T from(Tcl_Interp *interp, Tcl_Obj *obj) 61 | { 62 | return tcl_cast::from(interp, obj); 63 | } 64 | 65 | static Tcl_Obj * to(Tcl_Interp *interp, T const & v) { 66 | return tcl_cast::to(interp, v); 67 | } 68 | }; 69 | 70 | 71 | // the following specializations are implemented 72 | 73 | template <> 74 | struct tcl_cast 75 | { 76 | static int from(Tcl_Interp *, Tcl_Obj *); 77 | static Tcl_Obj * to(Tcl_Interp *, int const &); 78 | }; 79 | 80 | template <> 81 | struct tcl_cast 82 | { 83 | static long from(Tcl_Interp *, Tcl_Obj *); 84 | static Tcl_Obj * to(Tcl_Interp *, long const &); 85 | }; 86 | 87 | template <> 88 | struct tcl_cast 89 | { 90 | static long long from(Tcl_Interp *, Tcl_Obj *); 91 | static Tcl_Obj * to(Tcl_Interp *, long long const &); 92 | }; 93 | 94 | template <> 95 | struct tcl_cast 96 | { 97 | static bool from(Tcl_Interp *, Tcl_Obj *); 98 | static Tcl_Obj * to(Tcl_Interp *, bool const &); 99 | }; 100 | 101 | template <> 102 | struct tcl_cast 103 | { 104 | static double from(Tcl_Interp *, Tcl_Obj *); 105 | static Tcl_Obj * to(Tcl_Interp *, double const &); 106 | }; 107 | 108 | template <> 109 | struct tcl_cast 110 | { 111 | static std::string from(Tcl_Interp *, Tcl_Obj *); 112 | static Tcl_Obj * to(Tcl_Interp *, std::string const &); 113 | }; 114 | 115 | template <> 116 | struct tcl_cast 117 | { 118 | static char const * from(Tcl_Interp *, Tcl_Obj *); 119 | static Tcl_Obj * to(Tcl_Interp *, char const * const &); 120 | }; 121 | 122 | template <> 123 | struct tcl_cast > 124 | { 125 | static std::vector from(Tcl_Interp *, Tcl_Obj *); 126 | static Tcl_Obj * to(Tcl_Interp *, std::vector const &); 127 | }; 128 | 129 | template <> 130 | struct tcl_cast 131 | { 132 | static object from(Tcl_Interp *, Tcl_Obj *); 133 | static Tcl_Obj * to(Tcl_Interp *, object const &); 134 | }; 135 | -------------------------------------------------------------------------------- /details/dispatchers.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2004-2006, Maciej Sobczak 3 | // 4 | // Permission to copy, use, modify, sell and distribute this software 5 | // is granted provided this copyright notice appears in all copies. 6 | // This software is provided "as is" without express or implied 7 | // warranty, and with no claim as to its suitability for any purpose. 8 | // 9 | 10 | // Note: this file is not supposed to be a stand-alone header 11 | 12 | 13 | // the dispatch class is used to execute the callback functor and to 14 | // capture its return value 15 | // further dispatch specialization ignores the res 16 | 17 | template 18 | struct dispatch 19 | { 20 | template 21 | static void do_dispatch(Tcl_Interp *interp, Functor f) 22 | { 23 | R res = f(); 24 | set_result(interp, res); 25 | } 26 | 27 | template 28 | static void do_dispatch(Tcl_Interp *interp, Functor f, T1 t1) 29 | { 30 | R res = f(t1); 31 | set_result(interp, res); 32 | } 33 | 34 | template 35 | static void do_dispatch(Tcl_Interp *interp, Functor f, T1 t1, T2 t2) 36 | { 37 | R res = f(t1, t2); 38 | set_result(interp, res); 39 | } 40 | 41 | template 42 | static void do_dispatch(Tcl_Interp *interp, Functor f, 43 | T1 t1, T2 t2, T3 t3) 44 | { 45 | R res = f(t1, t2, t3); 46 | set_result(interp, res); 47 | } 48 | 49 | template 51 | static void do_dispatch(Tcl_Interp *interp, Functor f, 52 | T1 t1, T2 t2, T3 t3, T4 t4) 53 | { 54 | R res = f(t1, t2, t3, t4); 55 | set_result(interp, res); 56 | } 57 | 58 | template 60 | static void do_dispatch(Tcl_Interp *interp, Functor f, 61 | T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) 62 | { 63 | R res = f(t1, t2, t3, t4, t5); 64 | set_result(interp, res); 65 | } 66 | 67 | template 69 | static void do_dispatch(Tcl_Interp *interp, Functor f, 70 | T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) 71 | { 72 | R res = f(t1, t2, t3, t4, t5, t6); 73 | set_result(interp, res); 74 | } 75 | 76 | template 78 | static void do_dispatch(Tcl_Interp *interp, Functor f, 79 | T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) 80 | { 81 | R res = f(t1, t2, t3, t4, t5, t6, t7); 82 | set_result(interp, res); 83 | } 84 | 85 | template 87 | static void do_dispatch(Tcl_Interp *interp, Functor f, 88 | T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) 89 | { 90 | R res = f(t1, t2, t3, t4, t5, t6, t7, t8); 91 | set_result(interp, res); 92 | } 93 | 94 | template 97 | static void do_dispatch(Tcl_Interp *interp, Functor f, 98 | T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9) 99 | { 100 | R res = f(t1, t2, t3, t4, t5, t6, t7, t8, t9); 101 | set_result(interp, res); 102 | } 103 | }; 104 | 105 | template <> 106 | struct dispatch 107 | { 108 | template 109 | static void do_dispatch(Tcl_Interp *, Functor f) 110 | { 111 | f(); 112 | } 113 | 114 | template 115 | static void do_dispatch(Tcl_Interp *, Functor f, T1 t1) 116 | { 117 | f(t1); 118 | } 119 | 120 | template 121 | static void do_dispatch(Tcl_Interp *, Functor f, T1 t1, T2 t2) 122 | { 123 | f(t1, t2); 124 | } 125 | 126 | template 127 | static void do_dispatch(Tcl_Interp *, Functor f, 128 | T1 t1, T2 t2, T3 t3) 129 | { 130 | f(t1, t2, t3); 131 | } 132 | 133 | template 135 | static void do_dispatch(Tcl_Interp *, Functor f, 136 | T1 t1, T2 t2, T3 t3, T4 t4) 137 | { 138 | f(t1, t2, t3, t4); 139 | } 140 | 141 | template 143 | static void do_dispatch(Tcl_Interp *, Functor f, 144 | T1 t1, T2 t2, T3 t3, T4 t4, T5 t5) 145 | { 146 | f(t1, t2, t3, t4, t5); 147 | } 148 | 149 | template 151 | static void do_dispatch(Tcl_Interp *, Functor f, 152 | T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6) 153 | { 154 | f(t1, t2, t3, t4, t5, t6); 155 | } 156 | 157 | template 159 | static void do_dispatch(Tcl_Interp *, Functor f, 160 | T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7) 161 | { 162 | f(t1, t2, t3, t4, t5, t6, t7); 163 | } 164 | 165 | template 167 | static void do_dispatch(Tcl_Interp *, Functor f, 168 | T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8) 169 | { 170 | f(t1, t2, t3, t4, t5, t6, t7, t8); 171 | } 172 | 173 | template 176 | static void do_dispatch(Tcl_Interp *, Functor f, 177 | T1 t1, T2 t2, T3 t3, T4 t4, T5 t5, T6 t6, T7 t7, T8 t8, T9 t9) 178 | { 179 | f(t1, t2, t3, t4, t5, t6, t7, t8, t9); 180 | } 181 | }; 182 | -------------------------------------------------------------------------------- /details/metahelpers.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2004-2006, Maciej Sobczak 3 | // 4 | // Permission to copy, use, modify, sell and distribute this software 5 | // is granted provided this copyright notice appears in all copies. 6 | // This software is provided "as is" without express or implied 7 | // warranty, and with no claim as to its suitability for any purpose. 8 | // 9 | 10 | // Note: this file is not supposed to be a stand-alone header 11 | 12 | 13 | template 16 | struct get_callback_type_for_construct 17 | { 18 | typedef callback9 type; 19 | }; 20 | 21 | template 23 | struct get_callback_type_for_construct< 24 | C, T1, T2, T3, T4, T5, T6, T7, T8, void> 25 | { 26 | typedef callback8 type; 27 | }; 28 | 29 | template 31 | struct get_callback_type_for_construct< 32 | C, T1, T2, T3, T4, T5, T6, T7, void, void> 33 | { 34 | typedef callback7 type; 35 | }; 36 | 37 | template 39 | struct get_callback_type_for_construct< 40 | C, T1, T2, T3, T4, T5, T6, void, void, void> 41 | { 42 | typedef callback6 type; 43 | }; 44 | 45 | template 47 | struct get_callback_type_for_construct< 48 | C, T1, T2, T3, T4, T5, void, void, void, void> 49 | { 50 | typedef callback5 type; 51 | }; 52 | 53 | template 54 | struct get_callback_type_for_construct< 55 | C, T1, T2, T3, T4, void, void, void, void, void> 56 | { 57 | typedef callback4 type; 58 | }; 59 | 60 | template 61 | struct get_callback_type_for_construct< 62 | C, T1, T2, T3, void, void, void, void, void, void> 63 | { 64 | typedef callback3 type; 65 | }; 66 | 67 | template 68 | struct get_callback_type_for_construct< 69 | C, T1, T2, void, void, void, void, void, void, void> 70 | { 71 | typedef callback2 type; 72 | }; 73 | 74 | template 75 | struct get_callback_type_for_construct< 76 | C, T1, void, void, void, void, void, void, void, void> 77 | { 78 | typedef callback1 type; 79 | }; 80 | 81 | template 82 | struct get_callback_type_for_construct< 83 | C, void, void, void, void, void, void, void, void, void> 84 | { 85 | typedef callback0 type; 86 | }; 87 | -------------------------------------------------------------------------------- /details/methods.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2004-2006, Maciej Sobczak 3 | // 4 | // Permission to copy, use, modify, sell and distribute this software 5 | // is granted provided this copyright notice appears in all copies. 6 | // This software is provided "as is" without express or implied 7 | // warranty, and with no claim as to its suitability for any purpose. 8 | // 9 | 10 | // Note: this file is not supposed to be a stand-alone header 11 | 12 | 13 | template 14 | class method0 : public object_cmd_base 15 | { 16 | typedef R (C::*mem_type)(); 17 | typedef R (C::*cmem_type)() const; 18 | 19 | public: 20 | method0(mem_type f) : f_(f), cmem_(false) {} 21 | method0(cmem_type f) : cf_(f), cmem_(true) {} 22 | 23 | virtual void invoke(void *pv, Tcl_Interp *interp, 24 | int, Tcl_Obj * CONST [], policies const &) 25 | { 26 | C *p = static_cast(pv); 27 | if (cmem_) 28 | { 29 | dispatch::do_dispatch(interp, boost::bind(cf_, p)); 30 | } 31 | else 32 | { 33 | dispatch::do_dispatch(interp, boost::bind(f_, p)); 34 | } 35 | } 36 | 37 | private: 38 | mem_type f_; 39 | cmem_type cf_; 40 | bool cmem_; 41 | }; 42 | 43 | template 44 | class method1 : public object_cmd_base 45 | { 46 | typedef R (C::*mem_type)(T1); 47 | typedef R (C::*cmem_type)(T1) const; 48 | 49 | public: 50 | method1(mem_type f) : f_(f), cmem_(false) {} 51 | method1(cmem_type f) : cf_(f), cmem_(true) {} 52 | 53 | virtual void invoke(void *pv, Tcl_Interp *interp, 54 | int objc, Tcl_Obj * CONST objv[], policies const &) 55 | { 56 | check_params_no(objc, 3); 57 | 58 | C *p = static_cast(pv); 59 | if (cmem_) 60 | { 61 | dispatch::template do_dispatch( 62 | interp, boost::bind(cf_, p, _1), 63 | tcl_cast::from(interp, objv[2])); 64 | } 65 | else 66 | { 67 | dispatch::template do_dispatch( 68 | interp, boost::bind(f_, p, _1), 69 | tcl_cast::from(interp, objv[2])); 70 | } 71 | } 72 | 73 | private: 74 | mem_type f_; 75 | cmem_type cf_; 76 | bool cmem_; 77 | }; 78 | 79 | template 80 | class method2 : public object_cmd_base 81 | { 82 | typedef R (C::*mem_type)(T1, T2); 83 | typedef R (C::*cmem_type)(T1, T2) const; 84 | 85 | public: 86 | method2(mem_type f) : f_(f), cmem_(false) {} 87 | method2(cmem_type f) : cf_(f), cmem_(true) {} 88 | 89 | virtual void invoke(void *pv, Tcl_Interp *interp, 90 | int objc, Tcl_Obj * CONST objv[], policies const &) 91 | { 92 | check_params_no(objc, 4); 93 | 94 | C *p = static_cast(pv); 95 | if (cmem_) 96 | { 97 | dispatch::template do_dispatch( 98 | interp, boost::bind(cf_, p, _1, _2), 99 | tcl_cast::from(interp, objv[2]), 100 | tcl_cast::from(interp, objv[3])); 101 | } 102 | else 103 | { 104 | dispatch::template do_dispatch( 105 | interp, boost::bind(f_, p, _1, _2), 106 | tcl_cast::from(interp, objv[2]), 107 | tcl_cast::from(interp, objv[3])); 108 | } 109 | } 110 | 111 | private: 112 | mem_type f_; 113 | cmem_type cf_; 114 | bool cmem_; 115 | }; 116 | 117 | template 118 | class method3 : public object_cmd_base 119 | { 120 | typedef R (C::*mem_type)(T1, T2, T3); 121 | typedef R (C::*cmem_type)(T1, T2, T3) const; 122 | 123 | public: 124 | method3(mem_type f) : f_(f), cmem_(false) {} 125 | method3(cmem_type f) : cf_(f), cmem_(true) {} 126 | 127 | virtual void invoke(void *pv, Tcl_Interp *interp, 128 | int objc, Tcl_Obj * CONST objv[], policies const &) 129 | { 130 | check_params_no(objc, 5); 131 | 132 | C *p = static_cast(pv); 133 | if (cmem_) 134 | { 135 | dispatch::template do_dispatch( 136 | interp, boost::bind(cf_, p, _1, _2, _3), 137 | tcl_cast::from(interp, objv[2]), 138 | tcl_cast::from(interp, objv[3]), 139 | tcl_cast::from(interp, objv[4])); 140 | } 141 | else 142 | { 143 | dispatch::template do_dispatch( 144 | interp, boost::bind(f_, p, _1, _2, _3), 145 | tcl_cast::from(interp, objv[2]), 146 | tcl_cast::from(interp, objv[3]), 147 | tcl_cast::from(interp, objv[4])); 148 | } 149 | } 150 | 151 | private: 152 | mem_type f_; 153 | cmem_type cf_; 154 | bool cmem_; 155 | }; 156 | 157 | template 159 | class method4 : public object_cmd_base 160 | { 161 | typedef R (C::*mem_type)(T1, T2, T3, T4); 162 | typedef R (C::*cmem_type)(T1, T2, T3, T4) const; 163 | 164 | public: 165 | method4(mem_type f) : f_(f), cmem_(false) {} 166 | method4(cmem_type f) : cf_(f), cmem_(true) {} 167 | 168 | virtual void invoke(void *pv, Tcl_Interp *interp, 169 | int objc, Tcl_Obj * CONST objv[], policies const &) 170 | { 171 | check_params_no(objc, 6); 172 | 173 | C *p = static_cast(pv); 174 | if (cmem_) 175 | { 176 | dispatch::template do_dispatch( 177 | interp, boost::bind(cf_, p, _1, _2, _3, _4), 178 | tcl_cast::from(interp, objv[2]), 179 | tcl_cast::from(interp, objv[3]), 180 | tcl_cast::from(interp, objv[4]), 181 | tcl_cast::from(interp, objv[5])); 182 | } 183 | else 184 | { 185 | dispatch::template do_dispatch( 186 | interp, boost::bind(f_, p, _1, _2, _3, _4), 187 | tcl_cast::from(interp, objv[2]), 188 | tcl_cast::from(interp, objv[3]), 189 | tcl_cast::from(interp, objv[4]), 190 | tcl_cast::from(interp, objv[5])); 191 | } 192 | } 193 | 194 | private: 195 | mem_type f_; 196 | cmem_type cf_; 197 | bool cmem_; 198 | }; 199 | 200 | template 202 | class method5 : public object_cmd_base 203 | { 204 | typedef R (C::*mem_type)(T1, T2, T3, T4, T5); 205 | typedef R (C::*cmem_type)(T1, T2, T3, T4, T5) const; 206 | 207 | public: 208 | method5(mem_type f) : f_(f), cmem_(false) {} 209 | method5(cmem_type f) : cf_(f), cmem_(true) {} 210 | 211 | virtual void invoke(void *pv, Tcl_Interp *interp, 212 | int objc, Tcl_Obj * CONST objv[], policies const &) 213 | { 214 | check_params_no(objc, 7); 215 | 216 | C *p = static_cast(pv); 217 | if (cmem_) 218 | { 219 | dispatch::template do_dispatch( 220 | interp, boost::bind(cf_, p, _1, _2, _3, _4, _5), 221 | tcl_cast::from(interp, objv[2]), 222 | tcl_cast::from(interp, objv[3]), 223 | tcl_cast::from(interp, objv[4]), 224 | tcl_cast::from(interp, objv[5]), 225 | tcl_cast::from(interp, objv[6])); 226 | } 227 | else 228 | { 229 | dispatch::template do_dispatch( 230 | interp, boost::bind(f_, p, _1, _2, _3, _4, _5), 231 | tcl_cast::from(interp, objv[2]), 232 | tcl_cast::from(interp, objv[3]), 233 | tcl_cast::from(interp, objv[4]), 234 | tcl_cast::from(interp, objv[5]), 235 | tcl_cast::from(interp, objv[6])); 236 | } 237 | } 238 | 239 | private: 240 | mem_type f_; 241 | cmem_type cf_; 242 | bool cmem_; 243 | }; 244 | 245 | template 247 | class method6 : public object_cmd_base 248 | { 249 | typedef R (C::*mem_type)(T1, T2, T3, T4, T5, T6); 250 | typedef R (C::*cmem_type)(T1, T2, T3, T4, T5, T6) const; 251 | 252 | public: 253 | method6(mem_type f) : f_(f), cmem_(false) {} 254 | method6(cmem_type f) : cf_(f), cmem_(true) {} 255 | 256 | virtual void invoke(void *pv, Tcl_Interp *interp, 257 | int objc, Tcl_Obj * CONST objv[], policies const &) 258 | { 259 | check_params_no(objc, 8); 260 | 261 | C *p = static_cast(pv); 262 | if (cmem_) 263 | { 264 | dispatch::template do_dispatch( 265 | interp, boost::bind(cf_, p, _1, _2, _3, _4, _5, _6), 266 | tcl_cast::from(interp, objv[2]), 267 | tcl_cast::from(interp, objv[3]), 268 | tcl_cast::from(interp, objv[4]), 269 | tcl_cast::from(interp, objv[5]), 270 | tcl_cast::from(interp, objv[6]), 271 | tcl_cast::from(interp, objv[7])); 272 | } 273 | else 274 | { 275 | dispatch::template do_dispatch( 276 | interp, boost::bind(f_, p, _1, _2, _3, _4, _5, _6), 277 | tcl_cast::from(interp, objv[2]), 278 | tcl_cast::from(interp, objv[3]), 279 | tcl_cast::from(interp, objv[4]), 280 | tcl_cast::from(interp, objv[5]), 281 | tcl_cast::from(interp, objv[6]), 282 | tcl_cast::from(interp, objv[7])); 283 | } 284 | } 285 | 286 | private: 287 | mem_type f_; 288 | cmem_type cf_; 289 | bool cmem_; 290 | }; 291 | 292 | template 294 | class method7 : public object_cmd_base 295 | { 296 | typedef R (C::*mem_type)(T1, T2, T3, T4, T5, T6, T7); 297 | typedef R (C::*cmem_type)(T1, T2, T3, T4, T5, T6, T7) const; 298 | 299 | public: 300 | method7(mem_type f) : f_(f), cmem_(false) {} 301 | method7(cmem_type f) : cf_(f), cmem_(true) {} 302 | 303 | virtual void invoke(void *pv, Tcl_Interp *interp, 304 | int objc, Tcl_Obj * CONST objv[], policies const &) 305 | { 306 | check_params_no(objc, 9); 307 | 308 | C *p = static_cast(pv); 309 | if (cmem_) 310 | { 311 | dispatch::template do_dispatch( 312 | interp, boost::bind(cf_, p, _1, _2, _3, _4, _5, _6, _7), 313 | tcl_cast::from(interp, objv[2]), 314 | tcl_cast::from(interp, objv[3]), 315 | tcl_cast::from(interp, objv[4]), 316 | tcl_cast::from(interp, objv[5]), 317 | tcl_cast::from(interp, objv[6]), 318 | tcl_cast::from(interp, objv[7]), 319 | tcl_cast::from(interp, objv[8])); 320 | } 321 | else 322 | { 323 | dispatch::template do_dispatch( 324 | interp, boost::bind(f_, p, _1, _2, _3, _4, _5, _6, _7), 325 | tcl_cast::from(interp, objv[2]), 326 | tcl_cast::from(interp, objv[3]), 327 | tcl_cast::from(interp, objv[4]), 328 | tcl_cast::from(interp, objv[5]), 329 | tcl_cast::from(interp, objv[6]), 330 | tcl_cast::from(interp, objv[7]), 331 | tcl_cast::from(interp, objv[8])); 332 | } 333 | } 334 | 335 | private: 336 | mem_type f_; 337 | cmem_type cf_; 338 | bool cmem_; 339 | }; 340 | 341 | template 343 | class method8 : public object_cmd_base 344 | { 345 | typedef R (C::*mem_type)(T1, T2, T3, T4, T5, T6, T7, T8); 346 | typedef R (C::*cmem_type)(T1, T2, T3, T4, T5, T6, T7, T8) const; 347 | 348 | public: 349 | method8(mem_type f) : f_(f), cmem_(false) {} 350 | method8(cmem_type f) : cf_(f), cmem_(true) {} 351 | 352 | virtual void invoke(void *pv, Tcl_Interp *interp, 353 | int objc, Tcl_Obj * CONST objv[], policies const &) 354 | { 355 | check_params_no(objc, 10); 356 | 357 | C *p = static_cast(pv); 358 | if (cmem_) 359 | { 360 | dispatch::template do_dispatch< 361 | T1, T2, T3, T4, T5, T6, T7, T8>( 362 | interp, boost::bind(cf_, p, 363 | _1, _2, _3, _4, _5, _6, _7, _8), 364 | tcl_cast::from(interp, objv[2]), 365 | tcl_cast::from(interp, objv[3]), 366 | tcl_cast::from(interp, objv[4]), 367 | tcl_cast::from(interp, objv[5]), 368 | tcl_cast::from(interp, objv[6]), 369 | tcl_cast::from(interp, objv[7]), 370 | tcl_cast::from(interp, objv[8]), 371 | tcl_cast::from(interp, objv[9])); 372 | } 373 | else 374 | { 375 | dispatch::template do_dispatch< 376 | T1, T2, T3, T4, T5, T6, T7, T8>( 377 | interp, boost::bind(f_, p, 378 | _1, _2, _3, _4, _5, _6, _7, _8), 379 | tcl_cast::from(interp, objv[2]), 380 | tcl_cast::from(interp, objv[3]), 381 | tcl_cast::from(interp, objv[4]), 382 | tcl_cast::from(interp, objv[5]), 383 | tcl_cast::from(interp, objv[6]), 384 | tcl_cast::from(interp, objv[7]), 385 | tcl_cast::from(interp, objv[8]), 386 | tcl_cast::from(interp, objv[9])); 387 | } 388 | } 389 | 390 | private: 391 | mem_type f_; 392 | cmem_type cf_; 393 | bool cmem_; 394 | }; 395 | 396 | template 399 | class method9 : public object_cmd_base 400 | { 401 | typedef R (C::*mem_type)(T1, T2, T3, T4, T5, T6, T7, T8, T9); 402 | typedef R (C::*cmem_type)(T1, T2, T3, T4, T5, T6, T7, T8, T9) const; 403 | 404 | public: 405 | method9(mem_type f) : f_(f), cmem_(false) {} 406 | method9(cmem_type f) : cf_(f), cmem_(true) {} 407 | 408 | virtual void invoke(void *pv, Tcl_Interp *interp, 409 | int objc, Tcl_Obj * CONST objv[], policies const &) 410 | { 411 | check_params_no(objc, 11); 412 | 413 | C *p = static_cast(pv); 414 | if (cmem_) 415 | { 416 | dispatch::template do_dispatch< 417 | T1, T2, T3, T4, T5, T6, T7, T8, T9>( 418 | interp, boost::bind(cf_, p, 419 | _1, _2, _3, _4, _5, _6, _7, _8, _9), 420 | tcl_cast::from(interp, objv[2]), 421 | tcl_cast::from(interp, objv[3]), 422 | tcl_cast::from(interp, objv[4]), 423 | tcl_cast::from(interp, objv[5]), 424 | tcl_cast::from(interp, objv[6]), 425 | tcl_cast::from(interp, objv[7]), 426 | tcl_cast::from(interp, objv[8]), 427 | tcl_cast::from(interp, objv[9]), 428 | tcl_cast::from(interp, objv[10])); 429 | } 430 | else 431 | { 432 | dispatch::template do_dispatch< 433 | T1, T2, T3, T4, T5, T6, T7, T8, T9>( 434 | interp, boost::bind(f_, p, 435 | _1, _2, _3, _4, _5, _6, _7, _8, _9), 436 | tcl_cast::from(interp, objv[2]), 437 | tcl_cast::from(interp, objv[3]), 438 | tcl_cast::from(interp, objv[4]), 439 | tcl_cast::from(interp, objv[5]), 440 | tcl_cast::from(interp, objv[6]), 441 | tcl_cast::from(interp, objv[7]), 442 | tcl_cast::from(interp, objv[8]), 443 | tcl_cast::from(interp, objv[9]), 444 | tcl_cast::from(interp, objv[10])); 445 | } 446 | } 447 | 448 | private: 449 | mem_type f_; 450 | cmem_type cf_; 451 | bool cmem_; 452 | }; 453 | -------------------------------------------------------------------------------- /details/methods_v.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2004-2006, Maciej Sobczak 3 | // 4 | // Permission to copy, use, modify, sell and distribute this software 5 | // is granted provided this copyright notice appears in all copies. 6 | // This software is provided "as is" without express or implied 7 | // warranty, and with no claim as to its suitability for any purpose. 8 | // 9 | 10 | // Note: this file is not supposed to be a stand-alone header 11 | 12 | 13 | template 14 | class method1 : public object_cmd_base 15 | { 16 | typedef object const & T1; 17 | typedef R (C::*mem_type)(T1); 18 | typedef R (C::*cmem_type)(T1) const; 19 | enum { var_start = 2 }; 20 | 21 | public: 22 | method1(mem_type f) : f_(f), cmem_(false) {} 23 | method1(cmem_type f) : cf_(f), cmem_(true) {} 24 | 25 | virtual void invoke(void *pv, Tcl_Interp *interp, 26 | int objc, Tcl_Obj * CONST objv[], policies const &pol) 27 | { 28 | C *p = static_cast(pv); 29 | 30 | object t1 = get_var_params(interp, objc, objv, var_start, pol); 31 | 32 | if (cmem_) 33 | { 34 | dispatch::template do_dispatch( 35 | interp, boost::bind(cf_, p, _1), 36 | t1); 37 | } 38 | else 39 | { 40 | dispatch::template do_dispatch( 41 | interp, boost::bind(f_, p, _1), 42 | t1); 43 | } 44 | } 45 | 46 | private: 47 | mem_type f_; 48 | cmem_type cf_; 49 | bool cmem_; 50 | }; 51 | 52 | template 53 | class method2 : public object_cmd_base 54 | { 55 | typedef object const & T2; 56 | typedef R (C::*mem_type)(T1, T2); 57 | typedef R (C::*cmem_type)(T1, T2) const; 58 | enum { var_start = 3 }; 59 | 60 | public: 61 | method2(mem_type f) : f_(f), cmem_(false) {} 62 | method2(cmem_type f) : cf_(f), cmem_(true) {} 63 | 64 | virtual void invoke(void *pv, Tcl_Interp *interp, 65 | int objc, Tcl_Obj * CONST objv[], policies const &pol) 66 | { 67 | C *p = static_cast(pv); 68 | 69 | object t2 = get_var_params(interp, objc, objv, var_start, pol); 70 | 71 | if (cmem_) 72 | { 73 | dispatch::template do_dispatch( 74 | interp, boost::bind(cf_, p, _1, _2), 75 | tcl_cast::from(interp, objv[2]), 76 | t2); 77 | } 78 | else 79 | { 80 | dispatch::template do_dispatch( 81 | interp, boost::bind(f_, p, _1, _2), 82 | tcl_cast::from(interp, objv[2]), 83 | t2); 84 | } 85 | } 86 | 87 | private: 88 | mem_type f_; 89 | cmem_type cf_; 90 | bool cmem_; 91 | }; 92 | 93 | template 94 | class method3 : public object_cmd_base 95 | { 96 | typedef object const & T3; 97 | typedef R (C::*mem_type)(T1, T2, T3); 98 | typedef R (C::*cmem_type)(T1, T2, T3) const; 99 | enum { var_start = 4 }; 100 | 101 | public: 102 | method3(mem_type f) : f_(f), cmem_(false) {} 103 | method3(cmem_type f) : cf_(f), cmem_(true) {} 104 | 105 | virtual void invoke(void *pv, Tcl_Interp *interp, 106 | int objc, Tcl_Obj * CONST objv[], policies const &pol) 107 | { 108 | C *p = static_cast(pv); 109 | 110 | object t3 = get_var_params(interp, objc, objv, var_start, pol); 111 | 112 | if (cmem_) 113 | { 114 | dispatch::template do_dispatch( 115 | interp, boost::bind(cf_, p, _1, _2, _3), 116 | tcl_cast::from(interp, objv[2]), 117 | tcl_cast::from(interp, objv[3]), 118 | t3); 119 | } 120 | else 121 | { 122 | dispatch::template do_dispatch( 123 | interp, boost::bind(f_, p, _1, _2, _3), 124 | tcl_cast::from(interp, objv[2]), 125 | tcl_cast::from(interp, objv[3]), 126 | t3); 127 | } 128 | } 129 | 130 | private: 131 | mem_type f_; 132 | cmem_type cf_; 133 | bool cmem_; 134 | }; 135 | 136 | template 137 | class method4 : public object_cmd_base 138 | { 139 | typedef object const & T4; 140 | typedef R (C::*mem_type)(T1, T2, T3, T4); 141 | typedef R (C::*cmem_type)(T1, T2, T3, T4) const; 142 | enum { var_start = 5 }; 143 | 144 | public: 145 | method4(mem_type f) : f_(f), cmem_(false) {} 146 | method4(cmem_type f) : cf_(f), cmem_(true) {} 147 | 148 | virtual void invoke(void *pv, Tcl_Interp *interp, 149 | int objc, Tcl_Obj * CONST objv[], policies const &pol) 150 | { 151 | C *p = static_cast(pv); 152 | 153 | object t4 = get_var_params(interp, objc, objv, var_start, pol); 154 | 155 | if (cmem_) 156 | { 157 | dispatch::template do_dispatch( 158 | interp, boost::bind(cf_, p, _1, _2, _3, _4), 159 | tcl_cast::from(interp, objv[2]), 160 | tcl_cast::from(interp, objv[3]), 161 | tcl_cast::from(interp, objv[4]), 162 | t4); 163 | } 164 | else 165 | { 166 | dispatch::template do_dispatch( 167 | interp, boost::bind(f_, p, _1, _2, _3, _4), 168 | tcl_cast::from(interp, objv[2]), 169 | tcl_cast::from(interp, objv[3]), 170 | tcl_cast::from(interp, objv[4]), 171 | t4); 172 | } 173 | } 174 | 175 | private: 176 | mem_type f_; 177 | cmem_type cf_; 178 | bool cmem_; 179 | }; 180 | 181 | template 183 | class method5 : public object_cmd_base 184 | { 185 | typedef object const & T5; 186 | typedef R (C::*mem_type)(T1, T2, T3, T4, T5); 187 | typedef R (C::*cmem_type)(T1, T2, T3, T4, T5) const; 188 | enum { var_start = 6 }; 189 | 190 | public: 191 | method5(mem_type f) : f_(f), cmem_(false) {} 192 | method5(cmem_type f) : cf_(f), cmem_(true) {} 193 | 194 | virtual void invoke(void *pv, Tcl_Interp *interp, 195 | int objc, Tcl_Obj * CONST objv[], policies const &pol) 196 | { 197 | C *p = static_cast(pv); 198 | 199 | object t5 = get_var_params(interp, objc, objv, var_start, pol); 200 | 201 | if (cmem_) 202 | { 203 | dispatch::template do_dispatch( 204 | interp, boost::bind(cf_, p, _1, _2, _3, _4, _5), 205 | tcl_cast::from(interp, objv[2]), 206 | tcl_cast::from(interp, objv[3]), 207 | tcl_cast::from(interp, objv[4]), 208 | tcl_cast::from(interp, objv[5]), 209 | t5); 210 | } 211 | else 212 | { 213 | dispatch::template do_dispatch( 214 | interp, boost::bind(f_, p, _1, _2, _3, _4, _5), 215 | tcl_cast::from(interp, objv[2]), 216 | tcl_cast::from(interp, objv[3]), 217 | tcl_cast::from(interp, objv[4]), 218 | tcl_cast::from(interp, objv[5]), 219 | t5); 220 | } 221 | } 222 | 223 | private: 224 | mem_type f_; 225 | cmem_type cf_; 226 | bool cmem_; 227 | }; 228 | 229 | template 231 | class method6 232 | : public object_cmd_base 233 | { 234 | typedef object const & T6; 235 | typedef R (C::*mem_type)(T1, T2, T3, T4, T5, T6); 236 | typedef R (C::*cmem_type)(T1, T2, T3, T4, T5, T6) const; 237 | enum { var_start = 7 }; 238 | 239 | public: 240 | method6(mem_type f) : f_(f), cmem_(false) {} 241 | method6(cmem_type f) : cf_(f), cmem_(true) {} 242 | 243 | virtual void invoke(void *pv, Tcl_Interp *interp, 244 | int objc, Tcl_Obj * CONST objv[], policies const &pol) 245 | { 246 | C *p = static_cast(pv); 247 | 248 | object t6 = get_var_params(interp, objc, objv, var_start, pol); 249 | 250 | if (cmem_) 251 | { 252 | dispatch::template do_dispatch( 253 | interp, boost::bind(cf_, p, _1, _2, _3, _4, _5, _6), 254 | tcl_cast::from(interp, objv[2]), 255 | tcl_cast::from(interp, objv[3]), 256 | tcl_cast::from(interp, objv[4]), 257 | tcl_cast::from(interp, objv[5]), 258 | tcl_cast::from(interp, objv[6]), 259 | t6); 260 | } 261 | else 262 | { 263 | dispatch::template do_dispatch( 264 | interp, boost::bind(f_, p, _1, _2, _3, _4, _5, _6), 265 | tcl_cast::from(interp, objv[2]), 266 | tcl_cast::from(interp, objv[3]), 267 | tcl_cast::from(interp, objv[4]), 268 | tcl_cast::from(interp, objv[5]), 269 | tcl_cast::from(interp, objv[6]), 270 | t6); 271 | } 272 | } 273 | 274 | private: 275 | mem_type f_; 276 | cmem_type cf_; 277 | bool cmem_; 278 | }; 279 | 280 | template 282 | class method7 283 | : public object_cmd_base 284 | { 285 | typedef object const & T7; 286 | typedef R (C::*mem_type)(T1, T2, T3, T4, T5, T6, T7); 287 | typedef R (C::*cmem_type)(T1, T2, T3, T4, T5, T6, T7) const; 288 | enum { var_start = 8 }; 289 | 290 | public: 291 | method7(mem_type f) : f_(f), cmem_(false) {} 292 | method7(cmem_type f) : cf_(f), cmem_(true) {} 293 | 294 | virtual void invoke(void *pv, Tcl_Interp *interp, 295 | int objc, Tcl_Obj * CONST objv[], policies const &pol) 296 | { 297 | C *p = static_cast(pv); 298 | 299 | object t7 = get_var_params(interp, objc, objv, var_start, pol); 300 | 301 | if (cmem_) 302 | { 303 | dispatch::template do_dispatch( 304 | interp, boost::bind(cf_, p, _1, _2, _3, _4, _5, _6, _7), 305 | tcl_cast::from(interp, objv[2]), 306 | tcl_cast::from(interp, objv[3]), 307 | tcl_cast::from(interp, objv[4]), 308 | tcl_cast::from(interp, objv[5]), 309 | tcl_cast::from(interp, objv[6]), 310 | tcl_cast::from(interp, objv[7]), 311 | t7); 312 | } 313 | else 314 | { 315 | dispatch::template do_dispatch( 316 | interp, boost::bind(f_, p, _1, _2, _3, _4, _5, _6, _7), 317 | tcl_cast::from(interp, objv[2]), 318 | tcl_cast::from(interp, objv[3]), 319 | tcl_cast::from(interp, objv[4]), 320 | tcl_cast::from(interp, objv[5]), 321 | tcl_cast::from(interp, objv[6]), 322 | tcl_cast::from(interp, objv[7]), 323 | t7); 324 | } 325 | } 326 | 327 | private: 328 | mem_type f_; 329 | cmem_type cf_; 330 | bool cmem_; 331 | }; 332 | 333 | template 335 | class method8 336 | : public object_cmd_base 337 | { 338 | typedef object const & T8; 339 | typedef R (C::*mem_type)(T1, T2, T3, T4, T5, T6, T7, T8); 340 | typedef R (C::*cmem_type)(T1, T2, T3, T4, T5, T6, T7, T8) const; 341 | enum { var_start = 9 }; 342 | 343 | public: 344 | method8(mem_type f) : f_(f), cmem_(false) {} 345 | method8(cmem_type f) : cf_(f), cmem_(true) {} 346 | 347 | virtual void invoke(void *pv, Tcl_Interp *interp, 348 | int objc, Tcl_Obj * CONST objv[], policies const &pol) 349 | { 350 | C *p = static_cast(pv); 351 | 352 | object t8 = get_var_params(interp, objc, objv, var_start, pol); 353 | 354 | if (cmem_) 355 | { 356 | dispatch::template do_dispatch< 357 | T1, T2, T3, T4, T5, T6, T7, T8>( 358 | interp, boost::bind(cf_, p, 359 | _1, _2, _3, _4, _5, _6, _7, _8), 360 | tcl_cast::from(interp, objv[2]), 361 | tcl_cast::from(interp, objv[3]), 362 | tcl_cast::from(interp, objv[4]), 363 | tcl_cast::from(interp, objv[5]), 364 | tcl_cast::from(interp, objv[6]), 365 | tcl_cast::from(interp, objv[7]), 366 | tcl_cast::from(interp, objv[8]), 367 | t8); 368 | } 369 | else 370 | { 371 | dispatch::template do_dispatch< 372 | T1, T2, T3, T4, T5, T6, T7, T8>( 373 | interp, boost::bind(f_, p, 374 | _1, _2, _3, _4, _5, _6, _7, _8), 375 | tcl_cast::from(interp, objv[2]), 376 | tcl_cast::from(interp, objv[3]), 377 | tcl_cast::from(interp, objv[4]), 378 | tcl_cast::from(interp, objv[5]), 379 | tcl_cast::from(interp, objv[6]), 380 | tcl_cast::from(interp, objv[7]), 381 | tcl_cast::from(interp, objv[8]), 382 | t8); 383 | } 384 | } 385 | 386 | private: 387 | mem_type f_; 388 | cmem_type cf_; 389 | bool cmem_; 390 | }; 391 | 392 | template 394 | class method9 395 | : public object_cmd_base 396 | { 397 | typedef object const & T9; 398 | typedef R (C::*mem_type)(T1, T2, T3, T4, T5, T6, T7, T8, T9); 399 | typedef R (C::*cmem_type)(T1, T2, T3, T4, T5, T6, T7, T8, T9) const; 400 | enum { var_start = 10 }; 401 | 402 | public: 403 | method9(mem_type f) : f_(f), cmem_(false) {} 404 | method9(cmem_type f) : cf_(f), cmem_(true) {} 405 | 406 | virtual void invoke(void *pv, Tcl_Interp *interp, 407 | int objc, Tcl_Obj * CONST objv[], policies const &pol) 408 | { 409 | C *p = static_cast(pv); 410 | 411 | object t9 = get_var_params(interp, objc, objv, var_start, pol); 412 | 413 | if (cmem_) 414 | { 415 | dispatch::template do_dispatch< 416 | T1, T2, T3, T4, T5, T6, T7, T8, T9>( 417 | interp, boost::bind(cf_, p, 418 | _1, _2, _3, _4, _5, _6, _7, _8, _9), 419 | tcl_cast::from(interp, objv[2]), 420 | tcl_cast::from(interp, objv[3]), 421 | tcl_cast::from(interp, objv[4]), 422 | tcl_cast::from(interp, objv[5]), 423 | tcl_cast::from(interp, objv[6]), 424 | tcl_cast::from(interp, objv[7]), 425 | tcl_cast::from(interp, objv[8]), 426 | tcl_cast::from(interp, objv[9]), 427 | t9); 428 | } 429 | else 430 | { 431 | dispatch::template do_dispatch< 432 | T1, T2, T3, T4, T5, T6, T7, T8, T9>( 433 | interp, boost::bind(f_, p, 434 | _1, _2, _3, _4, _5, _6, _7, _8, _9), 435 | tcl_cast::from(interp, objv[2]), 436 | tcl_cast::from(interp, objv[3]), 437 | tcl_cast::from(interp, objv[4]), 438 | tcl_cast::from(interp, objv[5]), 439 | tcl_cast::from(interp, objv[6]), 440 | tcl_cast::from(interp, objv[7]), 441 | tcl_cast::from(interp, objv[8]), 442 | tcl_cast::from(interp, objv[9]), 443 | t9); 444 | } 445 | } 446 | 447 | private: 448 | mem_type f_; 449 | cmem_type cf_; 450 | bool cmem_; 451 | }; 452 | -------------------------------------------------------------------------------- /details/trace.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2012, Wei Song 2 | // 3 | // Permission to copy, use, modify, sell and distribute this software 4 | // is granted provided this copyright notice appears in all copies. 5 | // This software is provided "as is" without express or implied 6 | // warranty, and with no claim as to its suitability for any purpose. 7 | // 8 | 9 | // this is not a stand alone header file 10 | 11 | class trace_base { 12 | public: 13 | virtual ~trace_base() {} 14 | 15 | virtual void invoke(Tcl_Interp *interp, 16 | ClientData, const char *, const char *, int) = 0; 17 | }; 18 | 19 | template 20 | class trace : public trace_base { 21 | typedef VT (*functor_type) (VT const &, CDT *); 22 | public: 23 | trace(functor_type f) : f_(f){} 24 | virtual ~trace() {} 25 | 26 | virtual void invoke(Tcl_Interp *interp, ClientData cData, 27 | const char * VarName, const char *index, int flag) { 28 | // fetch the variable 29 | Tcl_Obj *var = Tcl_GetVar2Ex(interp, VarName, index, flag); 30 | VT orig = tcl_cast::from(interp, var); 31 | // run the trace 32 | VT rv = f_(orig, static_cast(cData)); 33 | if(rv != orig) { 34 | // reset the variable 35 | var = tcl_cast::to(interp, rv); 36 | Tcl_Obj *prv = Tcl_SetVar2Ex(interp, VarName, index, var, flag); 37 | assert(prv == var); 38 | } 39 | } 40 | 41 | private: 42 | functor_type f_; 43 | }; 44 | 45 | // Local Variables: 46 | // mode: c++ 47 | // End: 48 | -------------------------------------------------------------------------------- /doc/callpolicies.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Cpptcl 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 | View on GitHub 20 | 21 |

Cpptcl

22 |

C++/Tcl, a library that allows to easily integrate C++ and Tcl.

23 | 24 |
25 | Download this project as a .zip file 26 | Download this project as a tar.gz file 27 |
28 |
29 |
30 | 31 | 32 |
33 |
34 | 35 | [prev][top][next]
37 |

Call Policies

38 | Factories and 39 | sinks
40 |
41 | C++ has extremely rich type system. You can see this when you expose 42 | some free or member function:
43 |
i.def("fun", fun);
 44 | 

45 | The name of the function, fun, is enough for the C++/Tcl 46 | libray to discover the following information:
47 |
    48 |
  • Whether the function returns anything and what exactly.
  • 49 |
  • Whether it has any parameters, how many of them and what are 50 | their types.
    51 |
  • 52 |
53 | Sadly, these two pieces of information are sometimes not enough.
54 | Consider the following C++ functions:
55 |
SomeClass * produce() {
 56 |   return new SomeClass();
 57 | }
 58 | 
 59 | void consume(SomeClass *p) {
 60 |   // ...
 61 |   delete p;
 62 | }
 63 | 

64 | These two functions can be exposed this way:
65 |
i.def("produce", produce);
 66 | i.def("consume", consume);
 67 | 

68 | After doing so, you can safely use them like here:
69 |
% set object [produce]
 70 | p0x807b790
 71 | % consume $object
 72 | 

73 | The problem is that the produce command will not register 74 | any new Tcl command that would be responsible for managing member 75 | function calls or explicit object destruction, because, simply, it has 76 | no idea to which class definition (in the Tcl sense, not the C++ sense) 77 | the returned object belongs. In other words, the object name that is 78 | returned by the produce command has no meaning to the Tcl 79 | interpreter.
80 | To solve this problem, some additional information has to be provided 81 | while exposing the produce function:
82 |
i.def("produce", produce, factory("SomeClass"));
 83 | 

84 | As you see, there is additional parameter that provides hints to the 85 | C++/Tcl library. Such hints are called policies.
87 | The factory policy above provides the following 88 | information:
89 |
    90 |
  • The objects returned by the produce function are 91 | created with the new expression, or by other means. In 92 | any case - the pointer is returned.
    93 |
  • 94 |
  • These objects are meant to be handled as if they were created by 95 | regular constructor.
  • 96 |
      97 |
    • In particular, a new command has to be registered for each 98 | object returned by this function.
    • 99 |
    • This command should work as defined for the "SomeClass" 100 | Tcl class.
      101 |
    • 102 |
    103 |
104 |
105 | What about the consume function?
106 | There is also a problem - normally, objects are destroyed by explicit 107 | call to their -delete method. This call does two things:
108 |
    109 |
  • It deletes the objects (in the C++ sense), and
  • 110 |
  • it unregisters the Tcl command associated with that object.
  • 111 |
112 | We already know that the consume() function does the 113 | first thing. It is important also to do the second, otherwise the Tcl 114 | interpreter will be polluted with commands associated with non-existent 115 | objects (any call to such a command will result in undefined behaviour, 116 | which usually means a program crash).
117 | In other words, we have to provide a hint to the C++/Tcl library that 118 | the consume() function is a sink for objects:
120 |
i.def("consume", consume, sink(1));
121 | 

122 | The sink policy above says:
123 |
    124 |
  • The consume function takes responsibility for 125 | objects that are passed by its first (1) parameter.
  • 126 |
  • The object will be destroyed (or otherwise managed).
  • 127 |
  • The Tcl command associated with this object should be 128 | unregistered.
  • 129 |
130 | The following is a complete example with the use of policies:
131 |
// example5.cc
132 | 
133 | #include "cpptcl.h"
134 | #include <string>
135 | 
136 | using namespace std;
137 | using namespace Tcl;
138 | 
139 | class Person {
140 | public:
141 |   Person(string const &n) : name(n) {}
142 | 
143 |   void setName(string const &n) { name = n; }
144 |   string getName() { return name; }
145 | 
146 | private:
147 |   string name;
148 | };
149 | 
150 | // this is a factory function
151 | Person * makePerson(string const &name) {
152 |   return new Person(name);
153 | }
154 | 
155 | // this is a sink function
156 | void killPerson(Person *p) {
157 |   delete p;
158 | }
159 | 
160 | CPPTCL_MODULE(Mymodule, i) {
161 |   // note that the Person class is exposed without any constructor
162 |   i.class_<Person>("Person", no_init)
163 |     .def("setName", &Person::setName)
164 |     .def("getName", &Person::getName);
165 |   
166 |   i.def("makePerson", makePerson, factory("Person"));
167 |   i.def("killPerson", killPerson, sink(1));
168 | }
169 | 

170 | Now, let's try to exercise some interactive session with this:
171 |
% load ./mymodule.so 
172 | % set p [Person "Maciej"]
173 | invalid command name "Person"
174 | % 
175 | 

176 | As you see, the Tcl class Person has no constructor (this 177 | is the effect of providing the no_init policy when the 178 | class was exposed).
179 | Let's try another way:
180 |
% set p [makePerson "John"]
181 | p0x807b810
182 | % $p getName
183 | John
184 | % 
185 | 

186 | It works fine. Now:
187 |
% killPerson $p
188 | % $p getName
189 | invalid command name "p0x807b810"
190 | % 
191 | 

192 |
193 | Interestingly, a single function may need to combine several policies 194 | at once:
195 |
ClassA * create(int i, ClassB *p1, string const &s, ClassC *p2) {
196 |   // consume both p1 and p2 pointers
197 |   // and create new object:
198 |   return new ClassA();
199 | }
200 | 

201 | This function needs to combine three policies:
202 |
    203 |
  1. The factory policy, because it returns new objects.
  2. 204 |
  3. The sink policy on its second parameter.
  4. 205 |
  5. The sink policy on its fourth parameter.
    206 |
  6. 207 |
208 | The following definition does it:
209 |
i.def("create", create, factory("ClassA").sink(2).sink(4));
210 | 

211 | As you see, policies can be chained. Their order is not important, 212 | apart from the fact that the factory policy can be 213 | related to only one class, so it is the last factory 214 | policy in the chain that is effective.
215 |
216 |
217 | Variadic 218 | functions
219 |
220 | Another thing that can be controlled from policies is whether the 221 | function is variadic (whether it can accept variable number of 222 | arguments) or not.
223 | This feature is supported for:
224 |
    225 |
  • free functions
  • 226 |
  • constructors
  • 227 |
  • class methods
    228 |
  • 229 |
230 | In order for the function (or constructor or method) to be variadic, both of the following conditions 232 | must be true:
233 |
    234 |
  1. The type of last (or the only) parameter must be object 235 | const &
  2. 236 |
  3. The variadic() policy must be provided when 237 | defining that function.
  4. 238 |
239 | The last formal parameter is of the generic object type 240 | and it allows to retrieve both single values and lists.
241 | An example may help:
242 |
void fun(int a, int b, object const &c);
243 | 
244 | // later:
245 |   i.def("fun", fun);
246 | 

247 | Above, the fun() function is defined in the interpreter as having exactly three parameters.
249 | If more arguments are provided, they are discarded. If less, an error 250 | is reported.
251 | Now, consider the following change:
252 |
void fun(int a, int b, object const &c);
253 | 
254 | // later:
255 | i.def("fun", fun, variadic());
256 | 

257 | With the variadic() policy, the function will accept:
258 |
    259 |
  • two integer arguments - in that case, the c 260 | parameter will be an empty object
  • 261 |
  • three arguments - in that case, c will have the 262 | value of the third argument
  • 263 |
  • more - c will be a list of all arguments except the 264 | first two integer values.
  • 265 |
266 | Similarly, a constructor with variable list of parameters may be 267 | defined as:
268 |
class MyClass {
269 | public:
270 |   MyClass(int a, object const &b);
271 |   void fun();
272 | };
273 | 
274 | // later:
275 | i.class_<MyClass>("MyClass", init<int, object const &>(), variadic())
276 |   .def("fun", &MyClass::fun);
277 | 

278 | Note that the last parameter in the constructor has type object 279 | const & and that the variadic() policy was 280 | provided.
281 | This constructor will accept 1, 2 or more arguments.
282 |
283 | Of course, the variadic class methods can be defined in the same way:
284 |
class MyClass {
285 | public:
286 |   void fun(object const &a);
287 | };
288 | 
289 | // later:
290 | i.class_<MyClass>("MyClass")
291 |   .def("fun", &MyClass::fun, variadic());
292 | 

293 | As you see, the special, last parameter may be the only one, or 294 | preceded by any number of "normal" parameters.
295 |
296 | The possibility to define a variadic function is currently the only way 297 | to write commands that accept more than 9 arguments.
298 |
299 | The variadic() policy may be combined (in any order) with 300 | other policies.
301 |
302 | The following is a full example of module that defines one variadic 303 | function:
304 |
#include "cpptcl.h"
305 | 
306 | using namespace Tcl;
307 | 
308 | int sumAll(object const &argv) {
309 |   interpreter i(argv.get_interp(), false);
310 | 
311 |   int sum = 0;
312 | 
313 |   size_t argc = argv.length(i);
314 |   for (size_t indx = 0; indx != argc; ++indx) {
315 |     object o(argv.at(i, indx));
316 |     sum += o.get<int>(i);
317 |   }
318 | 
319 |   return sum;
320 | }
321 | 
322 | CPPTCL_MODULE(Mymodule, i) {
323 |   i.def("sum", sumAll, variadic());
324 | }
325 | 

326 | This module can be used from the Tcl interpreter like here;
327 |
% load ./mymodule.so 
328 | % sum
329 | 0
330 | % sum 5
331 | 5
332 | % sum 5 6 7
333 | 18
334 | % 
335 | 

336 | 337 |
338 |
339 | 340 | 341 | 347 | 348 | 349 | 350 | 351 | 352 | -------------------------------------------------------------------------------- /doc/classes.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Cpptcl 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 | View on GitHub 20 | 21 |

Cpptcl

22 |

C++/Tcl, a library that allows to easily integrate C++ and Tcl.

23 | 24 |
25 | Download this project as a .zip file 26 | Download this project as a tar.gz file 27 |
28 |
29 |
30 | 31 | 32 |
33 |
34 | 35 | 36 | 37 | [prev][top][next]
39 |

Exposing Classes
40 |

41 | Exposing classes is a little bit more involving, since there is more 42 | than name that needs to be defined.
43 | Let's suppose that we have the following C++ class:
44 |
class Person {
 45 | public:
 46 |   void setName(string const &n) { name = n; }
 47 |   string getName() { return name; }
 48 | 
 49 | private:
 50 |   string name;
 51 | };
 52 | 

53 | We can expose this class in some extension (or to the embedded 54 | interpreter) like this:
55 |
CPPTCL_MODULE(Mymodule, i) {
 56 |   i.class_<Person>("Person")
 57 |     .def("setName", &Person::setName);
 58 |     .def("getName", &Person::getName);
 59 | }
 60 | 

61 | Note: The i parameter to the CPPTCL_MODULE macro is a 62 | name that you 63 | later use to refer to the interpreter. You can choose whatever name you 64 | like. The rest of the code is the same as if the following object was 65 | declared in the C++ program:
66 |
interpreter i;
 67 | 

68 | Anyway - as you see, the class is defined using the class_ 69 | member function template, called on the interpreter object (it could 70 | not be named "class", since that is a keyword in C++).
71 | The string name that is provided as a parameter to the class_ 72 | function is a name that will be visible to the Tcl scripts - again, it 73 | does not have to be the name of the C++ class that you use in code.
74 |
75 |

Member functions

76 | This special class_ function returns an object that can 77 | be used to define class member functions, in the same expression and in 78 | a chained way.
79 | The above example is written in three lines just to make it more 80 | readable, but it is a single C++ instruction:
81 |
i.class_<Person>("Person").def("setName", &Person::setName).def("getName", &Person::getName);
 82 | 

83 | The rules for defining class member functions are the same as the rules 84 | used for Exposing Free Functions.
85 |
86 | After the class is exposed, it can be used in the following way (let's 87 | suppose that the above was compiled to the shared library named mymodule.so):
88 |
% load ./mymodule.so
 89 | % set p [Person]
 90 | p0x807b790
 91 | % $p setName "Maciej"
 92 | % $p getName
 93 | Maciej
 94 | %
 95 | 

96 | As you see, there is a Person command that creates and 97 | returns a new object. This is simply a constructor of our class. It 98 | returns a name of the new object (here it is p0x807b790 - it 99 | may be different on your machine or when you run the same program 100 | twice; you should not attach any external meaning to this name) and 101 | this name is immediately available as a new command, to use with member 102 | functions.
103 | For example, the expression:
104 |
% $p setName "Maciej"
105 | 

106 | calls the member function setName with the parameter "Maciej", 107 | on the object whose name is stored in the variable p.
108 | Later, the expression:
109 |
% $p getName
110 | 

111 | calls the member function getName without any parameters 112 | and it returns the string result of that call.
113 |
114 |

Constructors

115 | In the above example, the class Person has no 116 | constructors. Or, to be strict, it has a default constructor without 117 | parameters.
118 | The Person class could be exposed also in the following 119 | way:
120 |
i.class_<Person>("Person", init<>())
121 |   .def("setName", &Person::setName)
122 |   .def("getName", &Person::getName);
123 | 

124 | As you see, there is a special init object provided. It 125 | can carry information about the expected parameters that are needed for 126 | constructor, as in the following full example:
127 |
// example4.cc
128 | #include "cpptcl.h"
129 | #include 
130 | 
131 | using namespace std;
132 | using namespace Tcl;
133 | 
134 | class Person {
135 | public:
136 |   Person(string const &n) : name(n) {}
137 | 
138 |   void setName(string const &n) { name = n; }
139 |   string getName() { return name; }
140 | 
141 | private:
142 |   string name;
143 | };
144 | 
145 | CPPTCL_MODULE(Mymodule, i) {
146 |   i.class_<Person>("Person", init<string const &>())
147 |     .def("setName", &Person::setName)
148 |     .def("getName", &Person::getName);
149 | }
150 | 

151 | The init object can bring with it information about the 152 | number and the types of parameters needed by the constructor.
153 | Above, it declares that the constructor of class Person 154 | needs 1 parameter of type string const &.
155 | This means that we cannot use this exposed class from the Tcl script 156 | the same way as before:
157 |
% set p [Person]
158 | Too few arguments.
159 | % 
160 | 

161 | Instead, we have to provide required parameters:
162 |
% set p [Person "Maciej"]
163 | p0x807b7c0
164 | % $p getName
165 | Maciej
166 | %
167 | 

168 | Constructors with up to 9 parameters can be defined this way.
169 |
170 | Another form that may be sometimes useful is:
171 |
i.class_<Person>("Person", no_init)
172 |     .def("setName", &Person::setName);
173 |     .def("getName", &Person::getName);
174 | 

175 | This basically means that the exposed class has no 176 | constructors at all (or, to be strict, we do not want them to be 177 | visible from Tcl).
178 | Objects of such classes need to be created by separate factory 179 | functions.
180 |
181 |

Destructors

182 | There is additional "member function" that is automatically defined for 183 | each class, which is used for destroying the object:
184 |
% $p -delete
185 | 

186 | Once this is done, the object itself is destroyed and the associated 187 | command is removed from the interpreter.
188 | This means that the name stored in the variable p cannot be used for 189 | executing member functions any more:
190 |
% $p getName
191 | invalid command name "p0x807b790"
192 | %
193 | 

194 | 195 |
196 |
197 | 198 | 199 | 205 | 206 | 207 | 208 | 209 | 210 | -------------------------------------------------------------------------------- /doc/compiling.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Cpptcl 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 | View on GitHub 20 | 21 |

Cpptcl

22 |

C++/Tcl, a library that allows to easily integrate C++ and Tcl.

23 | 24 |
25 | Download this project as a .zip file 26 | Download this project as a tar.gz file 27 |
28 |
29 |
30 | 31 | 32 |
33 |
34 | 35 | 36 | [prev][top]
37 |

Compiling
38 |

39 | The C++/Tcl library consists of the following files:
40 |
    41 |
  • cpptcl.h - to be #included in your own 42 | projects,
    43 |
  • 44 |
  • cpptcl.cc - to be linked with your own projects,
  • 45 |
  • a couple of additional files in the details 46 | directory - this directory should be visible on the include search path.
    47 |
  • 48 |
49 | The C++/Tcl library depends on the Tcl core library and on the Boost 50 | library (see http://www.boost.org/). 51 | Any recent version of these two should work fine.
52 |
53 | Note: The Boost library is used in a way that does not require its 54 | installation nor even compilation. It is enough to just download the 55 | Boost distribution and unpack it in a place where it will be found by 56 | the compiler.
57 |
58 | Note: In its current version, the C++/Tcl library is not thread-safe in 59 | the sense that it should not be used in the multithreaded environment, 60 | where many threads can register new commands or use extended commands 61 | in scripts.
62 |

Unix, GNU/Linux

63 | On Unix-like systems, the following command is enough to compile a 64 | one-file C++/Tcl program (shown for FreeBSD):
65 | $ g++ myprog.cc cpptcl.cc -o myprog 66 | -I/usr/local/include/tcl8.4 -I/usr/local/include/boost_1_33_0 67 | -L/usr/local/lib -ltcl84
68 | Similarly, the following compiles a simple loadable shared module:
69 | $ g++ mymodule.cc cpptcl.cc -shared -o myprog 70 | -I/usr/local/include/tcl8.4 -I/usr/local/include/boost_1_33_0
71 | Depending on the specific Unix system, it may be necessary to use 72 | different search paths.
73 | Note also that a decent g++ compiler is necessary (in particular, g++ 74 | 2.95 or 2.96 will not work).
75 |
76 | The Makefiles provided with test and example programs 77 | should serve as good examples.
78 | 79 |
80 |
81 | 82 | 83 | 89 | 90 | 91 | 92 | 93 | 94 | -------------------------------------------------------------------------------- /doc/errors.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Cpptcl 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 | View on GitHub 20 | 21 |

Cpptcl

22 |

C++/Tcl, a library that allows to easily integrate C++ and Tcl.

23 | 24 |
25 | Download this project as a .zip file 26 | Download this project as a tar.gz file 27 |
28 |
29 |
30 | 31 | 32 |
33 |
34 | 35 | 36 | [prev][top][next]
38 |

Errors
39 |

40 | All Tcl errors, conversion errors and others that may take place when 41 | calling Tcl code from C++, are translated and reported as exceptions of 42 | the tcl_error type:
43 |
namespace Tcl {
44 |   class tcl_error : public std::runtime_error {
45 |     // ...
46 |    };
47 | }
48 | 

49 | This means that the simplest framework for handling such errors may 50 | look 51 | like:
52 |
int main() {
53 |   try {
54 |     interpreter i;
55 |     //...
56 |   } catch (tcl_error const &e) {
57 |     // some Tcl error
58 |   } catch (exception const &e) {
59 |     // some other error
60 |   }
61 | 

62 | On the other hand, when calling C++ from Tcl, all C++ exceptions are 63 | translated and presented as regular Tcl errors, with error message 64 | taken from the C++ exception, if it was from the std::exception 65 | family. For all other C++ exceptions, the "Unknown error." 66 | message is returned.
67 | 68 |
69 |
70 | 71 | 72 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /doc/freefun.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Cpptcl 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 | View on GitHub 20 | 21 |

Cpptcl

22 |

C++/Tcl, a library that allows to easily integrate C++ and Tcl.

23 | 24 |
25 | Download this project as a .zip file 26 | Download this project as a tar.gz file 27 |
28 |
29 |
30 | 31 | 32 |
33 |
34 | 35 | 36 | [prev][top][next]
38 |

Exposing Free Functions
39 |

40 | You have already seen an example of how to expose a free C++ function 41 | to the Tcl interpreter.
42 | No matter whether you write an extension module or embed Tcl in a C++ 43 | application, the way to expose a free function is alway the same:
44 |
i.def("tcl_function_name", cpp_function_name);
 45 | 

46 | where i is the name of the interpreter object.
47 | In the above example, the "tcl_function_name" is a name 48 | that will be visible to the Tcl scripts and the cpp_function_name 49 | is a name of (or a pointer to) the function in the C++ code.
50 | They do not have to be the same, although this is a usual practice, 51 | like in the Quick Start examples:
52 |
i.def("hello", hello);
 53 | 

54 | In fact, anything that is a valid command name in Tcl can be used as 55 | the first parameter.
56 | For example, let's suppose that we want to expose the following C++ 57 | function:
58 |
int sum(int a, int b) {
 59 |   return a + b;
 60 | }
 61 | 

62 | later we can define it in the interpreter like this:
63 |
i.def("sum", sum);
 64 | i.def("+", sum);
 65 | 

66 | so that we can call the sum function from Tcl like this:
67 |
add 3 4
 68 | 

69 | or:
70 |
+ 3 4
 71 | 

72 | As you see, the same function can be defined in the interpreter more 73 | than once, with different Tcl names.
74 | If you try to define some function with the name that is already 75 | registered, the old registration will be overwritten.
76 |
77 | You have also noticed that the exposed functions can have parameters 78 | and return values.
79 | Functions with up to 9 parameters can be exposed.
80 |
81 | At the moment, parameters and the return value of exposed functions can 82 | have the following types:
83 |
    84 |
  • std::string, char const *
    85 |
  • 86 |
  • int,
  • 87 |
  • long,
  • 88 |
  • bool,
  • 89 |
  • double,
  • 90 |
  • pointer to arbitrary type
  • 91 |
  • object
    92 |
  • 93 |
94 | In addition, the parameter of the function can be of type T 95 | const &, where T is any of the above.
96 | This means that only input 97 | parameters are supported (this may change in future versions of the 98 | libray).
99 | 100 |
Starting from version 1.1.4, the last argument of the C++ function can be used to pass an environment data (currently it must be a pointer) to the function, 101 | which is realized by using the ClientData field of the Tcl APIs. The following example shows the usage of this extra argument:
102 |
// example test7.cc
103 | 
104 | #include "cpptcl.h"
105 | 
106 | static int gdata = 2;        // a global data
107 | 
108 | void fun(int d, int * gd) {  // gd comes from environment
109 |   *gd += d;
110 | }
111 | 
112 | int main() {
113 |   interpreter i;
114 |   
115 |   i.def("fun", fun, &gdata); // send gdata to the Tcl fun
116 |   
117 |   i.eval("fun 10");          // only one argument is passed by Tcl command
118 |   assert(gdata == 12);       // check the global data is changed
119 | 
120 |   return 1;
121 | }
122 | 

123 | 124 | For variadic functions, the generic object type should be the second last argument if the last one is used for environment data. Such as:
125 |
// a function with 3 typed arguments, one variadic object and one environment data
126 | double fun(int d1, long d2, std::string d3, const object& var_arg, void * any_pointer);
127 | 

128 | 129 |
130 |
131 | 132 | 133 | 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /doc/goodies.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Cpptcl 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 | View on GitHub 20 | 21 |

Cpptcl

22 |

C++/Tcl, a library that allows to easily integrate C++ and Tcl.

23 | 24 |
25 | Download this project as a .zip file 26 | Download this project as a tar.gz file 27 |
28 |
29 |
30 | 31 | 32 |
33 |
34 | 35 | 36 | 37 | [prev][top][next]
39 |

Various Goodies
40 |

41 | This section of the documentation covers a couple of additional 42 | important features.
43 |
44 |

Package support

45 | It is possible to define a package name and version for the extension. 46 | Use the pkg_provide member function when defining a 47 | loadable module:
48 |
CPPTCL_MODULE(Mymodule, i) {
 49 |   i.pkg_provide("MyPackage", "3.4");
 50 |   // ...
 51 | }
 52 | 

53 | After loading this module inside the Tcl interpreter, the following 54 | command shows that the package is indeed provided:
55 |
% package provide MyPackage
 56 | 3.4
 57 | %
 58 | 

59 |

Stream evaluation

60 | It is possible to evaluate the contents of the input stream. One of the 61 | possible uses is the evaluation of the whole file:
62 |
ifstream f("somescript.tcl");
 63 | i.eval(f);
 64 | 

65 | Any object compatible with std::istream is accepted.
66 |

Tcl Namespaces

67 | Tcl supports namespaces. It is possible to define classes and functions 68 | within their own namespace by just prefixing the name with the 69 | namespace 70 | name:
71 |
i.def("NS::fun", fun);
 72 | 

73 | The above example defines a new function fun, which will 74 | be visible in the NS namespace.
75 | The problem is that the Tcl namespace needs to be created before any 76 | name is added to it. This can be done by simple script evaluation.
77 | Example:
78 |
CPPTCL_MODULE(Mymodule, i) {
 79 |   i.eval("namespace eval NS {}");
 80 |   i.def("NS::fun", fun);
 81 | }
 82 | 

83 |

Safe Tcl Interpreters

84 | Each Tcl interpreter can be turned into a safe interpreter, where dangerous 86 | commands (which are commands related to files, sockets, process 87 | control, etc.) cannot be called.
88 | This feature may be very useful when user-provided scripts are to be 89 | evaluated in the embedded Tcl interpreter.
90 | In order to make a safe interpreter, do this:
91 |
i.make_safe();
 92 | 

93 | Once the interpreter is made safe, it cannot be put back to its normal 94 | form.
95 |
96 |

Aliasing

97 | Aliasing is a powerful feature of Tcl. It allows to define links between two interpreters, so 99 | that when one command is invoked in one interpreter, it is just 100 | forwarded and executed within the second interpreter. This means that 101 | the given command will have access to the other interpreter's state 102 | (its commands, variables, etc.).
103 | This feature is useful when a "firewall" interpreter is created that 104 | provides access to only selected set of commands defined in another 105 | interpreter.
106 | In order to make an alias from interpreter i1 to 107 | interpreter i2, do this:
108 |
i1.create_alias("fun", i2, "otherFun");
109 | 

110 | The above instruction creates an alias in the interpreter i1, 111 | so that whenever the fun command is invoked in it, it will forward the 112 | call to the second interpreter, to the otherFun command.
113 | 114 | 115 |
116 |
117 | 118 | 119 | 125 | 126 | 127 | 128 | 129 | 130 | -------------------------------------------------------------------------------- /doc/images/bg_hr.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsong83/cpptcl/c5917b75de5f6fdace6dc2adee24e929961a8570/doc/images/bg_hr.png -------------------------------------------------------------------------------- /doc/images/blacktocat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsong83/cpptcl/c5917b75de5f6fdace6dc2adee24e929961a8570/doc/images/blacktocat.png -------------------------------------------------------------------------------- /doc/images/icon_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsong83/cpptcl/c5917b75de5f6fdace6dc2adee24e929961a8570/doc/images/icon_download.png -------------------------------------------------------------------------------- /doc/images/sprite_download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wsong83/cpptcl/c5917b75de5f6fdace6dc2adee24e929961a8570/doc/images/sprite_download.png -------------------------------------------------------------------------------- /doc/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Cpptcl 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 | View on GitHub 20 | 21 |

Cpptcl

22 |

C++/Tcl, a library that allows to easily integrate C++ and Tcl.

23 | 24 |
25 | Download this project as a .zip file 26 | Download this project as a tar.gz file 27 |
28 |
29 |
30 | 31 | 32 |
33 |
34 | 35 |

Version 1.1.4.001 (09/07/2012)


36 | 37 | Welcome to the C++/Tcl (original versions up to 1.1.3) 38 | library!
39 |
40 | This library was written for C++ and Tcl programmers.
41 | It was inspired by the Boost.Python 43 | library and was deliberately designed to provide a similar interface, 44 | taking into account the limitations of Tcl.
45 |
46 | The C++/Tcl library offers the following features:
47 |
    48 |
  1. Support for both extending Tcl with C++ modules and embedding Tcl 49 | in C++ applications.
  2. 50 |
  3. Possibility to expose free C++ functions as commands in Tcl.
  4. 51 |
  5. Possibility to define classes and class member functions, visible 52 | in Tcl in the style 53 | similar to SWIG 54 | wrappers.
  6. 55 |
  7. Possibility to manipulate Tcl lists and objects from the C++ code.
    56 |
  8. 57 |
58 |
59 | Quick Start
60 | 64 | Exposing Free Functions
65 | Exposing Classes
66 | 71 | Objects and Lists
72 | Call Policies
73 | 77 | Variable Traces
78 | 82 | Various Goodies
83 | 92 | Errors
93 | Compiling
94 | 95 | 96 |
97 |
98 | 99 | 100 | 106 | 107 | 108 | 109 | 110 | 111 | -------------------------------------------------------------------------------- /doc/javascripts/main.js: -------------------------------------------------------------------------------- 1 | console.log('This would be the main JS file.'); 2 | -------------------------------------------------------------------------------- /doc/objects.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Cpptcl 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 | View on GitHub 20 | 21 |

Cpptcl

22 |

C++/Tcl, a library that allows to easily integrate C++ and Tcl.

23 | 24 |
25 | Download this project as a .zip file 26 | Download this project as a tar.gz file 27 |
28 |
29 |
30 | 31 | 32 |
33 |
34 | 35 | 36 | 37 | [prev][top][next]
39 |

Objects and Lists

40 | In order to help with managing Tcl lists, there is an object wrapper 41 | that allows to manipulate Tcl objects.
42 | The class object provides the following members:
43 |
44 | 1. Constructors
45 |
object();
 46 | explicit object(bool b);
 47 | object(char const *buf, size_t size);
 48 | explicit object(double b);
 49 | explicit object(int i);
 50 | 
 51 | template <class InputIterator>
 52 | object(InputIterator first, InputIterator last);
 53 | 
 54 | explicit object(long i);
 55 | explicit object(char const *s);
 56 | explicit object(std::string const &s);
 57 | 

58 | The above constructors allow to create a Tcl object from common C++ 59 | types.
60 | The constructor accepting iterators is for the list creation. The 61 | provided iterator type should give either object or Tcl_Obj* 62 | type when dereferenced.
63 |
64 | 2. Copy constructors
65 |
explicit object(Tcl_Obj *o, bool shared = false);
 66 | object(object const &other, bool shared = false);
 67 | 

68 | If the shared flag is set, the newly created object 69 | wrapper will not duplicate the underlying Tcl object.
70 |
71 | 3. Assignment-related members
72 |
object & assign(bool b);
 73 | object & resize(size_t size);                        // byte array resize
 74 | object & assign(char const *buf, size_t size);       // byte array assignment
 75 | object & assign(double d);
 76 | object & assign(int i);
 77 | 
 78 | template <class InputIterator>
 79 | object & assign(InputIterator first, InputIterator last);
 80 | 
 81 | object & assign(long l);
 82 | object & assign(char const *s);
 83 | object & assign(std::string const &s);
 84 | object & assign(object const &o);
 85 | object & assign(Tcl_Obj *o);
 86 | 
 87 | object & operator=(bool b);
 88 | object & operator=(double d);
 89 | object & operator=(int i);
 90 | object & operator=(long l);
 91 | object & operator=(char const *s);
 92 | object & operator=(std::string const &s);
 93 | 
 94 | object & operator=(object const &o);
 95 | object & swap(object &other);
 96 | 

97 | The assign member function accepting iterators is for the 98 | list assignment. The provided iterator type should give either object 99 | or Tcl_Obj* type when dereferenced.
100 |
101 | 4. Non-modifying accessors
102 |
template <typename T>
103 | T get(interpreter &i) const;
104 | 
105 | char const * get() const;                       // string get
106 | char const * get(size_t &size) const;           // byte array get
107 | 
108 | size_t length(interpreter &i) const;            // returns list length
109 | object at(interpreter &i, size_t index) const;
110 | 
111 | Tcl_Obj * get_object() const { return obj_; }
112 | 

113 | The get<T> template is specialized for the 114 | following types:
115 |
    116 |
  • bool
  • 117 |
  • vector<char> (for byte array queries)
  • 118 |
  • double
  • 119 |
  • int
  • 120 |
  • long
  • 121 |
  • char const *
  • 122 |
  • std::string
    123 |
  • 124 |
125 | 5. List-related modifiers
126 |
object & append(interpreter &i, object const &o);
127 | object & append_list(interpreter &i, object const &o);
128 | 
129 | template <class InputIterator>
130 | object & replace(Interpreter &i, size_t index, size_t count,
131 |                  InputIterator first, InputIterator last);
132 | 
133 | object & replace(interpreter &i, size_t index, size_t count, object const &o);
134 | object & replace_list(interpreter &i, size_t index, size_t count, object const &o);
135 | 

136 | 6. Additional helpers
137 |
void set_interp(Tcl_Interp *interp);
138 | Tcl_Interp * get_interp() const;
139 | 

140 | These functions may help to transmit the information about the 141 | "current" interpreter when the C++ function accepting object 142 | parameter is called from Tcl.
143 | The set_interp function is automatically called by the 144 | underlying 145 | conversion logic, so that the C++ code can use the other function for 146 | accessing the interpreter.
147 | This may be useful when the C++ code needs to invoke other functions 148 | that may change the interpreter state.
149 |
150 | Note: If there is any need to extract the interpreter from the existing 151 | object, it may be helpful to wrap the resulting raw pointer into the interpreter 152 | object, which will not disrupt its normal lifetime:
153 |
interpreter i(o.get_interp(), false);
154 | 

155 | The second parameter given to the interpreter constructor 156 | means that the newly created i object will not claim 157 | ownership to the pointer received from get_interp().
158 | In other words, the destructor of the object i will not 159 | free the actual interpreter.
160 |
161 |
162 | Example:
163 |
164 | The following complete program creates the list of numbers, sorts it 165 | using the Tcl interpreter and prints the results on the console (note: 166 | this is not the most efficient way to sort numbers in C++!):
167 |
// example6.cc
168 | 
169 | #include "../cpptcl.h"
170 | #include <iostream>
171 | 
172 | using namespace std;
173 | using namespace Tcl;
174 | 
175 | int main() {
176 |   interpreter i;
177 | 
178 |   int numbers[] = {5, 7, 1, 6, 3, 9, 7};
179 |   size_t elems = sizeof(numbers) / sizeof(int);
180 | 
181 |   object tab;
182 |   for (size_t indx = 0; indx != elems; ++indx) {
183 |     tab.append(i, object(numbers[indx]));
184 |   }
185 | 
186 |   object cmd("lsort -integer");
187 |   cmd.append(i, tab);
188 | 
189 |   // here, cmd contains the following:
190 |   // lsort -integer {5 7 1 6 3 9 7}
191 | 
192 |   object result = i.eval(cmd);
193 | 
194 |   cout << "unsorted: ";
195 |   for (size_t indx = 0; indx != elems; ++indx) {
196 |     cout << numbers[indx] << ' ';
197 |    }
198 | 
199 |   cout << "\n  sorted: ";
200 |   elems = result.length(i);
201 |   for (size_t indx = 0; indx != elems; ++indx) {
202 |     object obj(result.at(i, indx));
203 |     int val = obj.get<int>(i);
204 | 
205 |     cout << val << ' ';
206 |   }
207 |   cout << '\n';
208 | }
209 | 

210 | When this program is run, it gives the following output:
211 |
$ ./example6
212 | unsorted: 5 7 1 6 3 9 7
213 |   sorted: 1 3 5 6 7 7 9
214 | $ 
215 | 

216 | In this example, an empty tab object is created and all 217 | numbers are appended to it to form a Tcl list of numbers.
218 | After that, the sorting command is composed and executed (as you see, 219 | the object can be passed for evaluation).
220 | The result of the command is retrieved also in the form of object 221 | wrapper, which is used to decompose the resulting list into its 222 | elements.
223 | 224 |
225 |
226 | 227 | 228 | 234 | 235 | 236 | 237 | 238 | 239 | -------------------------------------------------------------------------------- /doc/params.json: -------------------------------------------------------------------------------- 1 | {"tagline":"C++/Tcl, a library that allows to easily integrate C++ and Tcl.","body":"### Welcome to GitHub Pages.\r\nThis automatic page generator is the easiest way to create beautiful pages for all of your projects. Author your page content here using GitHub Flavored Markdown, select a template crafted by a designer, and publish. After your page is generated, you can check out the new branch:\r\n\r\n```\r\n$ cd your_repo_root/repo_name\r\n$ git fetch origin\r\n$ git checkout gh-pages\r\n```\r\n\r\nIf you're using the GitHub for Mac, simply sync your repository and you'll see the new branch.\r\n\r\n### Designer Templates\r\nWe've crafted some handsome templates for you to use. Go ahead and continue to layouts to browse through them. You can easily go back to edit your page before publishing. After publishing your page, you can revisit the page generator and switch to another theme. Your Page content will be preserved if it remained markdown format.\r\n\r\n### Rather Drive Stick?\r\nIf you prefer to not use the automatic generator, push a branch named `gh-pages` to your repository to create a page manually. In addition to supporting regular HTML content, GitHub Pages support Jekyll, a simple, blog aware static site generator written by our own Tom Preston-Werner. Jekyll makes it easy to create site-wide headers and footers without having to copy them across every page. It also offers intelligent blog support and other advanced templating features.\r\n\r\n### Authors and Contributors\r\nYou can @mention a GitHub username to generate a link to their profile. The resulting `` element will link to the contributor's GitHub Profile. For example: In 2007, Chris Wanstrath (@defunkt), PJ Hyett (@pjhyett), and Tom Preston-Werner (@mojombo) founded GitHub.\r\n\r\n### Support or Contact\r\nHaving trouble with Pages? Check out the documentation at http://help.github.com/pages or contact support@github.com and we’ll help you sort it out.","note":"Don't delete this file! It's used internally to help with page regeneration.","google":"","name":"Cpptcl"} -------------------------------------------------------------------------------- /doc/quickstart.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Cpptcl 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 | View on GitHub 20 | 21 |

Cpptcl

22 |

C++/Tcl, a library that allows to easily integrate C++ and Tcl.

23 | 24 |
25 | Download this project as a .zip file 26 | Download this project as a tar.gz file 27 |
28 |
29 |
30 | 31 | 32 |
33 |
34 | 35 | 36 | 37 | [top][next]
38 |

Quick Start

39 | The C++/Tcl library allows to easily integrate these two languages.
40 | It is easy to both extend the Tcl interpreter and to embed the Tcl 41 | interpreter in a regular C++ code.
42 |
43 |

Hello World (extending Tcl)
44 |

45 | Let's take the following C++ file:

46 |
// example1.cc
 47 | #include "cpptcl.h"
 48 | #include <iostream>
 49 | 
 50 | using namespace std;
 51 | 
 52 | void hello() {
 53 |   cout << "Hello C++/Tcl!" << endl;
 54 | }
 55 | 
 56 | CPPTCL_MODULE(Mymodule, i) {
 57 |   i.def("hello", hello);
 58 | }
 59 | 

60 | After compiling (let's suppose that the resulting shared library is 61 | named mymodule.so), we can do this:

62 |
$ tclsh
 63 | % load ./mymodule.so
 64 | % hello
 65 | Hello C++/Tcl!
 66 | % for {set i 0} {$i != 4} {incr i} { hello }
 67 | Hello C++/Tcl!
 68 | Hello C++/Tcl!
 69 | Hello C++/Tcl!
 70 | Hello C++/Tcl!
 71 | %
 72 | 

73 | In other words, the Tcl interpreter was extended with the loadable module 75 | (which is a shared library) that provides the definition of new command.

76 |
// example2.cc
 77 | 
 78 | #include "cpptcl.h"
 79 | #include <iostream>
 80 | #include <string>
 81 | 
 82 | using namespace std;
 83 | using namespace Tcl;
 84 | 
 85 | void hello() {
 86 |   cout << "Hello C++/Tcl!" << endl;
 87 | }
 88 | 
 89 | int main() {
 90 |   interpreter i;
 91 |   i.def("hello", hello);
 92 | 
 93 |   string script = "for {set i 0} {$i != 4} {incr i} { hello }";
 94 | 
 95 |   i.eval(script);
 96 | }
 97 | 

98 | After compiling, it gives the following result:
99 |
$ ./example2
100 | Hello C++/Tcl!
101 | Hello C++/Tcl!
102 | Hello C++/Tcl!
103 | Hello C++/Tcl!
104 | $
105 | 

106 | In other words, the Tcl interpreter exists in a C++ application as a 107 | regular object.
108 | It is possible to define new commands in this interpreter and execute 109 | arbitrary Tcl scripts in it, so that C++ and Tcl communicate with each 110 | other.
111 | 112 | 113 |
114 |
115 | 116 | 117 | 123 | 124 | 125 | 126 | 127 | 128 | -------------------------------------------------------------------------------- /doc/stylesheets/pygment_trac.css: -------------------------------------------------------------------------------- 1 | .highlight .hll { background-color: #ffffcc } 2 | .highlight { background: #f0f3f3; } 3 | .highlight .c { color: #0099FF; font-style: italic } /* Comment */ 4 | .highlight .err { color: #AA0000; background-color: #FFAAAA } /* Error */ 5 | .highlight .k { color: #006699; font-weight: bold } /* Keyword */ 6 | .highlight .o { color: #555555 } /* Operator */ 7 | .highlight .cm { color: #0099FF; font-style: italic } /* Comment.Multiline */ 8 | .highlight .cp { color: #009999 } /* Comment.Preproc */ 9 | .highlight .c1 { color: #0099FF; font-style: italic } /* Comment.Single */ 10 | .highlight .cs { color: #0099FF; font-weight: bold; font-style: italic } /* Comment.Special */ 11 | .highlight .gd { background-color: #FFCCCC; border: 1px solid #CC0000 } /* Generic.Deleted */ 12 | .highlight .ge { font-style: italic } /* Generic.Emph */ 13 | .highlight .gr { color: #FF0000 } /* Generic.Error */ 14 | .highlight .gh { color: #003300; font-weight: bold } /* Generic.Heading */ 15 | .highlight .gi { background-color: #CCFFCC; border: 1px solid #00CC00 } /* Generic.Inserted */ 16 | .highlight .go { color: #AAAAAA } /* Generic.Output */ 17 | .highlight .gp { color: #000099; font-weight: bold } /* Generic.Prompt */ 18 | .highlight .gs { font-weight: bold } /* Generic.Strong */ 19 | .highlight .gu { color: #003300; font-weight: bold } /* Generic.Subheading */ 20 | .highlight .gt { color: #99CC66 } /* Generic.Traceback */ 21 | .highlight .kc { color: #006699; font-weight: bold } /* Keyword.Constant */ 22 | .highlight .kd { color: #006699; font-weight: bold } /* Keyword.Declaration */ 23 | .highlight .kn { color: #006699; font-weight: bold } /* Keyword.Namespace */ 24 | .highlight .kp { color: #006699 } /* Keyword.Pseudo */ 25 | .highlight .kr { color: #006699; font-weight: bold } /* Keyword.Reserved */ 26 | .highlight .kt { color: #007788; font-weight: bold } /* Keyword.Type */ 27 | .highlight .m { color: #FF6600 } /* Literal.Number */ 28 | .highlight .s { color: #CC3300 } /* Literal.String */ 29 | .highlight .na { color: #330099 } /* Name.Attribute */ 30 | .highlight .nb { color: #336666 } /* Name.Builtin */ 31 | .highlight .nc { color: #00AA88; font-weight: bold } /* Name.Class */ 32 | .highlight .no { color: #336600 } /* Name.Constant */ 33 | .highlight .nd { color: #9999FF } /* Name.Decorator */ 34 | .highlight .ni { color: #999999; font-weight: bold } /* Name.Entity */ 35 | .highlight .ne { color: #CC0000; font-weight: bold } /* Name.Exception */ 36 | .highlight .nf { color: #CC00FF } /* Name.Function */ 37 | .highlight .nl { color: #9999FF } /* Name.Label */ 38 | .highlight .nn { color: #00CCFF; font-weight: bold } /* Name.Namespace */ 39 | .highlight .nt { color: #330099; font-weight: bold } /* Name.Tag */ 40 | .highlight .nv { color: #003333 } /* Name.Variable */ 41 | .highlight .ow { color: #000000; font-weight: bold } /* Operator.Word */ 42 | .highlight .w { color: #bbbbbb } /* Text.Whitespace */ 43 | .highlight .mf { color: #FF6600 } /* Literal.Number.Float */ 44 | .highlight .mh { color: #FF6600 } /* Literal.Number.Hex */ 45 | .highlight .mi { color: #FF6600 } /* Literal.Number.Integer */ 46 | .highlight .mo { color: #FF6600 } /* Literal.Number.Oct */ 47 | .highlight .sb { color: #CC3300 } /* Literal.String.Backtick */ 48 | .highlight .sc { color: #CC3300 } /* Literal.String.Char */ 49 | .highlight .sd { color: #CC3300; font-style: italic } /* Literal.String.Doc */ 50 | .highlight .s2 { color: #CC3300 } /* Literal.String.Double */ 51 | .highlight .se { color: #CC3300; font-weight: bold } /* Literal.String.Escape */ 52 | .highlight .sh { color: #CC3300 } /* Literal.String.Heredoc */ 53 | .highlight .si { color: #AA0000 } /* Literal.String.Interpol */ 54 | .highlight .sx { color: #CC3300 } /* Literal.String.Other */ 55 | .highlight .sr { color: #33AAAA } /* Literal.String.Regex */ 56 | .highlight .s1 { color: #CC3300 } /* Literal.String.Single */ 57 | .highlight .ss { color: #FFCC33 } /* Literal.String.Symbol */ 58 | .highlight .bp { color: #336666 } /* Name.Builtin.Pseudo */ 59 | .highlight .vc { color: #003333 } /* Name.Variable.Class */ 60 | .highlight .vg { color: #003333 } /* Name.Variable.Global */ 61 | .highlight .vi { color: #003333 } /* Name.Variable.Instance */ 62 | .highlight .il { color: #FF6600 } /* Literal.Number.Integer.Long */ 63 | 64 | .type-csharp .highlight .k { color: #0000FF } 65 | .type-csharp .highlight .kt { color: #0000FF } 66 | .type-csharp .highlight .nf { color: #000000; font-weight: normal } 67 | .type-csharp .highlight .nc { color: #2B91AF } 68 | .type-csharp .highlight .nn { color: #000000 } 69 | .type-csharp .highlight .s { color: #A31515 } 70 | .type-csharp .highlight .sc { color: #A31515 } 71 | -------------------------------------------------------------------------------- /doc/stylesheets/stylesheet.css: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | Slate Theme for Github Pages 3 | by Jason Costello, @jsncostello 4 | *******************************************************************************/ 5 | 6 | @import url(pygment_trac.css); 7 | 8 | /******************************************************************************* 9 | MeyerWeb Reset 10 | *******************************************************************************/ 11 | 12 | html, body, div, span, applet, object, iframe, 13 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 14 | a, abbr, acronym, address, big, cite, code, 15 | del, dfn, em, img, ins, kbd, q, s, samp, 16 | small, strike, strong, sub, sup, tt, var, 17 | b, u, i, center, 18 | dl, dt, dd, ol, ul, li, 19 | fieldset, form, label, legend, 20 | table, caption, tbody, tfoot, thead, tr, th, td, 21 | article, aside, canvas, details, embed, 22 | figure, figcaption, footer, header, hgroup, 23 | menu, nav, output, ruby, section, summary, 24 | time, mark, audio, video { 25 | margin: 0; 26 | padding: 0; 27 | border: 0; 28 | font: inherit; 29 | vertical-align: baseline; 30 | } 31 | 32 | /* HTML5 display-role reset for older browsers */ 33 | article, aside, details, figcaption, figure, 34 | footer, header, hgroup, menu, nav, section { 35 | display: block; 36 | } 37 | 38 | ol, ul { 39 | list-style: none; 40 | } 41 | 42 | blockquote, q { 43 | } 44 | 45 | table { 46 | border-collapse: collapse; 47 | border-spacing: 0; 48 | } 49 | 50 | a:focus { 51 | outline: none; 52 | } 53 | 54 | /******************************************************************************* 55 | Theme Styles 56 | *******************************************************************************/ 57 | 58 | body { 59 | box-sizing: border-box; 60 | color:#373737; 61 | background: #212121; 62 | font-size: 16px; 63 | font-family: 'Myriad Pro', Calibri, Helvetica, Arial, sans-serif; 64 | line-height: 1.5; 65 | -webkit-font-smoothing: antialiased; 66 | } 67 | 68 | h1, h2, h3, h4, h5, h6 { 69 | margin: 10px 0; 70 | font-weight: 700; 71 | color:#222222; 72 | font-family: 'Lucida Grande', 'Calibri', Helvetica, Arial, sans-serif; 73 | letter-spacing: -1px; 74 | } 75 | 76 | h1 { 77 | font-size: 36px; 78 | font-weight: 700; 79 | } 80 | 81 | h2 { 82 | padding-bottom: 10px; 83 | font-size: 32px; 84 | background: url('../images/bg_hr.png') repeat-x bottom; 85 | } 86 | 87 | h3 { 88 | font-size: 24px; 89 | } 90 | 91 | h4 { 92 | font-size: 21px; 93 | } 94 | 95 | h5 { 96 | font-size: 18px; 97 | } 98 | 99 | h6 { 100 | font-size: 16px; 101 | } 102 | 103 | p { 104 | margin: 10px 0 15px 0; 105 | } 106 | 107 | footer p { 108 | color: #f2f2f2; 109 | } 110 | 111 | a { 112 | text-decoration: none; 113 | color: #007edf; 114 | text-shadow: none; 115 | 116 | transition: color 0.5s ease; 117 | transition: text-shadow 0.5s ease; 118 | -webkit-transition: color 0.5s ease; 119 | -webkit-transition: text-shadow 0.5s ease; 120 | -moz-transition: color 0.5s ease; 121 | -moz-transition: text-shadow 0.5s ease; 122 | -o-transition: color 0.5s ease; 123 | -o-transition: text-shadow 0.5s ease; 124 | -ms-transition: color 0.5s ease; 125 | -ms-transition: text-shadow 0.5s ease; 126 | } 127 | 128 | #main_content a:hover { 129 | color: #0069ba; 130 | text-shadow: #0090ff 0px 0px 2px; 131 | } 132 | 133 | footer a:hover { 134 | color: #43adff; 135 | text-shadow: #0090ff 0px 0px 2px; 136 | } 137 | 138 | em { 139 | font-style: italic; 140 | } 141 | 142 | strong { 143 | font-weight: bold; 144 | } 145 | 146 | img { 147 | position: relative; 148 | margin: 0 auto; 149 | max-width: 739px; 150 | padding: 5px; 151 | margin: 10px 0 10px 0; 152 | border: 1px solid #ebebeb; 153 | 154 | box-shadow: 0 0 5px #ebebeb; 155 | -webkit-box-shadow: 0 0 5px #ebebeb; 156 | -moz-box-shadow: 0 0 5px #ebebeb; 157 | -o-box-shadow: 0 0 5px #ebebeb; 158 | -ms-box-shadow: 0 0 5px #ebebeb; 159 | } 160 | 161 | pre, code { 162 | width: 100%; 163 | color: #222; 164 | background-color: #fff; 165 | 166 | font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; 167 | font-size: 14px; 168 | 169 | border-radius: 2px; 170 | -moz-border-radius: 2px; 171 | -webkit-border-radius: 2px; 172 | 173 | 174 | 175 | } 176 | 177 | pre { 178 | width: 100%; 179 | padding: 10px; 180 | box-shadow: 0 0 10px rgba(0,0,0,.1); 181 | overflow: auto; 182 | } 183 | 184 | code { 185 | padding: 3px; 186 | margin: 0 3px; 187 | box-shadow: 0 0 10px rgba(0,0,0,.1); 188 | } 189 | 190 | pre code { 191 | display: block; 192 | box-shadow: none; 193 | } 194 | 195 | blockquote { 196 | color: #666; 197 | margin-bottom: 20px; 198 | padding: 0 0 0 20px; 199 | border-left: 3px solid #bbb; 200 | } 201 | 202 | ul, ol, dl { 203 | margin-bottom: 15px 204 | } 205 | 206 | ul li { 207 | list-style: inside; 208 | padding-left: 20px; 209 | } 210 | 211 | ol li { 212 | list-style: decimal inside; 213 | padding-left: 20px; 214 | } 215 | 216 | dl dt { 217 | font-weight: bold; 218 | } 219 | 220 | dl dd { 221 | padding-left: 20px; 222 | font-style: italic; 223 | } 224 | 225 | dl p { 226 | padding-left: 20px; 227 | font-style: italic; 228 | } 229 | 230 | hr { 231 | height: 1px; 232 | margin-bottom: 5px; 233 | border: none; 234 | background: url('../images/bg_hr.png') repeat-x center; 235 | } 236 | 237 | table { 238 | border: 1px solid #373737; 239 | margin-bottom: 20px; 240 | text-align: left; 241 | } 242 | 243 | th { 244 | font-family: 'Lucida Grande', 'Helvetica Neue', Helvetica, Arial, sans-serif; 245 | padding: 10px; 246 | background: #373737; 247 | color: #fff; 248 | } 249 | 250 | td { 251 | padding: 10px; 252 | border: 1px solid #373737; 253 | } 254 | 255 | form { 256 | background: #f2f2f2; 257 | padding: 20px; 258 | } 259 | 260 | img { 261 | width: 100%; 262 | max-width: 100%; 263 | } 264 | 265 | /******************************************************************************* 266 | Full-Width Styles 267 | *******************************************************************************/ 268 | 269 | .outer { 270 | width: 100%; 271 | } 272 | 273 | .inner { 274 | position: relative; 275 | max-width: 800px; 276 | padding: 20px 10px; 277 | margin: 0 auto; 278 | } 279 | 280 | #forkme_banner { 281 | display: block; 282 | position: absolute; 283 | top:0; 284 | right: 10px; 285 | z-index: 10; 286 | padding: 10px 50px 10px 10px; 287 | color: #fff; 288 | background: url('../images/blacktocat.png') #0090ff no-repeat 95% 50%; 289 | font-weight: 700; 290 | box-shadow: 0 0 10px rgba(0,0,0,.5); 291 | border-bottom-left-radius: 2px; 292 | border-bottom-right-radius: 2px; 293 | } 294 | 295 | #header_wrap { 296 | background: #212121; 297 | background: -moz-linear-gradient(top, #373737, #212121); 298 | background: -webkit-linear-gradient(top, #373737, #212121); 299 | background: -ms-linear-gradient(top, #373737, #212121); 300 | background: -o-linear-gradient(top, #373737, #212121); 301 | background: linear-gradient(top, #373737, #212121); 302 | } 303 | 304 | #header_wrap .inner { 305 | padding: 50px 10px 30px 10px; 306 | } 307 | 308 | #project_title { 309 | margin: 0; 310 | color: #fff; 311 | font-size: 42px; 312 | font-weight: 700; 313 | text-shadow: #111 0px 0px 10px; 314 | } 315 | 316 | #project_tagline { 317 | color: #fff; 318 | font-size: 24px; 319 | font-weight: 300; 320 | background: none; 321 | text-shadow: #111 0px 0px 10px; 322 | } 323 | 324 | #downloads { 325 | position: absolute; 326 | width: 210px; 327 | z-index: 10; 328 | bottom: -40px; 329 | right: 0; 330 | height: 70px; 331 | background: url('../images/icon_download.png') no-repeat 0% 90%; 332 | } 333 | 334 | .zip_download_link { 335 | display: block; 336 | float: right; 337 | width: 90px; 338 | height:70px; 339 | text-indent: -5000px; 340 | overflow: hidden; 341 | background: url(../images/sprite_download.png) no-repeat bottom left; 342 | } 343 | 344 | .tar_download_link { 345 | display: block; 346 | float: right; 347 | width: 90px; 348 | height:70px; 349 | text-indent: -5000px; 350 | overflow: hidden; 351 | background: url(../images/sprite_download.png) no-repeat bottom right; 352 | margin-left: 10px; 353 | } 354 | 355 | .zip_download_link:hover { 356 | background: url(../images/sprite_download.png) no-repeat top left; 357 | } 358 | 359 | .tar_download_link:hover { 360 | background: url(../images/sprite_download.png) no-repeat top right; 361 | } 362 | 363 | #main_content_wrap { 364 | background: #f2f2f2; 365 | border-top: 1px solid #111; 366 | border-bottom: 1px solid #111; 367 | } 368 | 369 | #main_content { 370 | padding-top: 40px; 371 | } 372 | 373 | #footer_wrap { 374 | background: #212121; 375 | } 376 | 377 | 378 | 379 | /******************************************************************************* 380 | Small Device Styles 381 | *******************************************************************************/ 382 | 383 | @media screen and (max-width: 480px) { 384 | body { 385 | font-size:14px; 386 | } 387 | 388 | #downloads { 389 | display: none; 390 | } 391 | 392 | .inner { 393 | min-width: 320px; 394 | max-width: 480px; 395 | } 396 | 397 | #project_title { 398 | font-size: 32px; 399 | } 400 | 401 | h1 { 402 | font-size: 28px; 403 | } 404 | 405 | h2 { 406 | font-size: 24px; 407 | } 408 | 409 | h3 { 410 | font-size: 21px; 411 | } 412 | 413 | h4 { 414 | font-size: 18px; 415 | } 416 | 417 | h5 { 418 | font-size: 14px; 419 | } 420 | 421 | h6 { 422 | font-size: 12px; 423 | } 424 | 425 | code, pre { 426 | min-width: 320px; 427 | max-width: 480px; 428 | font-size: 11px; 429 | } 430 | 431 | } 432 | -------------------------------------------------------------------------------- /doc/trace.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Cpptcl 12 | 13 | 14 | 15 | 16 | 17 |
18 |
19 | View on GitHub 20 | 21 |

Cpptcl

22 |

C++/Tcl, a library that allows to easily integrate C++ and Tcl.

23 | 24 |
25 | Download this project as a .zip file 26 | Download this project as a tar.gz file 27 |
28 |
29 |
30 | 31 | 32 |
33 |
34 | 35 | 36 | 37 | [prev][top][next]
39 |

Variable Traces
40 |

41 | Define and remove trace functions to Tcl variables.
42 |
43 | 44 |

Define a trace function

45 | 46 | Tcl allows users to define trace functions to monitor or even control the access of a Tcl variable.
47 |
48 | Starting from version 1.1.4.001, C++/Tcl provides easy interfaces to define read and write traces for Tcl variables. 49 | If a tcl variable is associated with a read trace, the trace function is called before the variable is read; therefor, the trace function can modify the variable value which results in a different value been read. On the other hand, for a write trace, it is called after the associated variable is written; therefore, the trace function can modify the actual value written to the variable. It is possible to use a write trace to implement a read-only variable.
50 |
51 | The trace function allowed in the C++/Tcl library must have the following format:
52 |
template<typename VT, typename CDT>
 53 | VT trace_function (VT const & var, CDT * cData);
 54 | 

55 | where VT is the value type of the Tcl variable, and CDT defines the type of user data structure passed to the trace function.
56 |
57 | As long as a data type T is supported by get<T> (see Objects and Lists, 4), it can be used as VT for the trace function.
58 |
59 | The trace function reads in the current value of the variable var and returns a new value. If the returned value is different with var, the returned value will be written to the traced Tcl variable.
60 |
61 | Currently, only a pointer pointing to a user data can be passed to the trace function (an absolute data will be lost).
62 |
63 | Several member methods are provided in Tcl::interpreter to define trace functions:
64 |
// define read trace
 65 | template<typename VT, typename CDT>
 66 | void interpreter::def_read_trace(const string& VarName, 
 67 |                                  const string& FunName, 
 68 |                                  VT (*proc)(VT const &, CDT *), CDT *cData = NULL);
 69 | 
 70 | template<typename VT, typename CDT>
 71 | void interpreter::def_read_trace(const string& VarName, unsigned int index, 
 72 |                                  const string& FunName, 
 73 |                                  VT (*proc)(VT const &, CDT *), CDT *cData = NULL);
 74 | 
 75 | // define write trace
 76 | template<typename VT, typename CDT>
 77 | void interpreter::def_write_trace(const string& VarName, 
 78 |                                   const string& FunName, 
 79 |                                   VT (*proc)(VT const &, CDT *), CDT *cData = NULL);
 80 | 
 81 | template<typename VT, typename CDT>
 82 | void interpreter::def_write_trace(const string& VarName, unsigned int index, 
 83 |                                   const string& FunName, 
 84 |                                   VT (*proc)(VT const &, CDT *), CDT *cData = NULL);
 85 | 

86 | where VarName is the name of the Tcl variable to be traced; index identifies the the index if only one element in an variable array is traced; FunName is an unique string to identify a trace function, otherwise the trace function is lost; proc is the real function pointer pointing to the trace function; and cData is the user data to be passed to the trace function.
87 |
88 | Tcl allows to trace a variable before it is define. This is actually saying a trace can be pre-set to an unknown variable and it will be called when the variable is actually set in Tcl. FunName is used as an id to identify a trace function. It is not necessary to pair a FunName with a trace function proc. Therefore, it is legal to define a trace function proc more than one time to the same variable using different FunNames. Tracing different variables using the same trace function is always allowed. When no user data is passed, argument cData can be omitted as it is NULL by default.
89 | 90 |

Remove a defined trace

91 | 92 | It is possible to remove a trace on the run. Several member methods are provide for this purpose:
93 |
// remove a read trace
 94 | void interpreter::undef_read_trace(const string& VarName, 
 95 |                                    const string& FunName = "");
 96 | 
 97 | void interpreter::undef_read_trace(const string& VarName, unsigned int index, 
 98 |                                    const string& FunName = "");
 99 | 
100 | // remove a write trace
101 | void interpreter::undef_write_trace(const string& VarName, 
102 |                                     const string& FunName = "");
103 | 
104 | void interpreter::undef_write_trace(const string& VarName, unsigned int index, 
105 |                                     const string& FunName = "");
106 | 
107 | // delete all traces
108 | void interpreter::undef_all_trace(const string& VarName);
109 | 
110 | void interpreter::undef_all_trace(const string& VarName, unsigned int index);
111 | 

112 | When FunName is not provided or assigned empty, all trace functions associated with the target variable are removed; otherwise, only the trace function identified by FunName is removed. undef_all_trace() is used to remove all traces associated with a variable.
113 | 114 |

Example

115 | The following simple example demonstrates how to use this feature. A more complicated example can be found in test8.cc.
116 |
// example of variable traces
117 | 
118 | #include "cpptcl.h"
119 | #include <iostream>
120 | 
121 | using std::cout;
122 | using std::endl;
123 | using std::string;
124 | using namespace Tcl;
125 | 
126 | 
127 | int read_trace(const int& v, void *) {
128 |   cout << "read trace triggered." << endl;
129 |   return v;
130 | }
131 | 
132 | int write_trace(const int& v, int * cd) {
133 |   cout << "write trace triggered." << endl;
134 |   
135 |   // set the user data to the current variable value
136 |   *cd = v;
137 |   
138 |   // modify the variable value
139 |   return v+1;                   
140 | }
141 | 
142 | int main() {
143 |   interpreter i;
144 |   int env = 5;     // user data
145 | 
146 |   i.def_read_trace("tcl_var", "read", read_trace);
147 |   i.def_write_trace("tcl_var", "write", write_trace, &env);
148 | 
149 |   // test write trace
150 |   string rv = i.eval("set tcl_var 20");
151 |   // stdout: write trace triggered.
152 |   assert(rv == "21");           // the actual value is 20 + 1
153 | 
154 |   // test read trace
155 |   i.eval("set tcl_var");
156 |   // stdout: read trace triggered.
157 | 
158 |   i.undef_read_trace("tcl_var", "read");
159 |   i.eval("set tcl_var");
160 |   // stdout: [nothing]
161 |   //   since read trace is removed
162 | 
163 |   i.undef_all_trace("tcl_var");
164 |   string rv1 = i.eval("set tcl_var 20");
165 |   // stdout: [nothing]
166 |   //   since write trace is removed
167 |   assert(rv1 == "20");           // back to normal behaviour
168 | }
169 | 

170 | 171 |
172 |
173 | 174 | 175 | 181 | 182 | 183 | 184 | 185 | 186 | -------------------------------------------------------------------------------- /examples/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2011-2012, Wei Song 2 | # 3 | # Permission to copy, use, modify, sell and distribute this software 4 | # is granted provided this copyright notice appears in all copies. 5 | # This software is provided "as is" without express or implied 6 | # warranty, and with no claim as to its suitability for any purpose. 7 | # 8 | 9 | INCDIRS = -I. -I.. 10 | 11 | OUTPUTS = example1.so example3.so example4.so example5.so example7.so 12 | 13 | all : ${OUTPUTS} example2 example6 14 | 15 | $(OUTPUTS) : %.so:%.cc ../cpptcl.o 16 | $(CXX) $(INCDIRS) $(CXXFLAGS) $< ../cpptcl.o $(SHARED_LINKFLAGS) -o $@ 17 | 18 | example2 : example2.cc ../cpptcl.o 19 | $(CXX) $(INCDIRS) $(CXXFLAGS) $< ../cpptcl.o $(OBJ_LINKFLAGS) -o $@ 20 | 21 | example6 : example6.cc ../cpptcl.o 22 | $(CXX) $(INCDIRS) $(CXXFLAGS) $< ../cpptcl.o $(OBJ_LINKFLAGS) -o $@ 23 | 24 | clean : 25 | -rm -f ${OUTPUTS} example2 example6 26 | -------------------------------------------------------------------------------- /examples/example1.cc: -------------------------------------------------------------------------------- 1 | // example1.cc 2 | 3 | #include "cpptcl.h" 4 | #include 5 | 6 | using namespace std; 7 | 8 | void hello() 9 | { 10 | cout << "Hello C++/Tcl!" << endl; 11 | } 12 | 13 | CPPTCL_MODULE(Mymodule, i) 14 | { 15 | i.def("hello", hello); 16 | } 17 | -------------------------------------------------------------------------------- /examples/example2.cc: -------------------------------------------------------------------------------- 1 | // example2.cc 2 | 3 | #include "cpptcl.h" 4 | #include 5 | #include 6 | 7 | using namespace std; 8 | using namespace Tcl; 9 | 10 | void hello() 11 | { 12 | cout << "Hello C++/Tcl!" << endl; 13 | } 14 | 15 | int main() 16 | { 17 | interpreter i; 18 | i.def("hello", hello); 19 | 20 | string script = "for {set i 0} {$i != 4} {incr i} { hello }"; 21 | 22 | i.eval(script); 23 | } 24 | -------------------------------------------------------------------------------- /examples/example3.cc: -------------------------------------------------------------------------------- 1 | // example3.cc 2 | 3 | #include "cpptcl.h" 4 | #include 5 | 6 | using namespace std; 7 | using namespace Tcl; 8 | 9 | class Person 10 | { 11 | public: 12 | void setName(string const &n) { name = n; } 13 | string getName() { return name; } 14 | 15 | private: 16 | string name; 17 | }; 18 | 19 | 20 | CPPTCL_MODULE(Mymodule, i) 21 | { 22 | i.class_("Person") 23 | .def("setName", &Person::setName) 24 | .def("getName", &Person::getName); 25 | 26 | // or, alternatively: 27 | 28 | //i.class_("Person", init<>()) 29 | // .def("setName", &Person::setName) 30 | // .def("getName", &Person::getName); 31 | } 32 | -------------------------------------------------------------------------------- /examples/example4.cc: -------------------------------------------------------------------------------- 1 | // example4.cc 2 | 3 | #include "cpptcl.h" 4 | #include 5 | 6 | using namespace std; 7 | using namespace Tcl; 8 | 9 | class Person 10 | { 11 | public: 12 | Person(string const &n) : name(n) {} 13 | 14 | void setName(string const &n) { name = n; } 15 | string getName() { return name; } 16 | 17 | private: 18 | string name; 19 | }; 20 | 21 | 22 | CPPTCL_MODULE(Mymodule, i) 23 | { 24 | i.class_("Person", init()) 25 | .def("setName", &Person::setName) 26 | .def("getName", &Person::getName); 27 | } 28 | -------------------------------------------------------------------------------- /examples/example5.cc: -------------------------------------------------------------------------------- 1 | // example5.cc 2 | 3 | #include "cpptcl.h" 4 | #include 5 | 6 | using namespace std; 7 | using namespace Tcl; 8 | 9 | class Person 10 | { 11 | public: 12 | Person(string const &n) : name(n) {} 13 | 14 | void setName(string const &n) { name = n; } 15 | string getName() { return name; } 16 | 17 | private: 18 | string name; 19 | }; 20 | 21 | // this is a factory function 22 | Person * makePerson(string const &name) 23 | { 24 | return new Person(name); 25 | } 26 | 27 | // this is a sink function 28 | void killPerson(Person *p) 29 | { 30 | delete p; 31 | } 32 | 33 | CPPTCL_MODULE(Mymodule, i) 34 | { 35 | // note that the Person class is exposed without any constructor 36 | i.class_("Person", no_init) 37 | .def("setName", &Person::setName) 38 | .def("getName", &Person::getName); 39 | 40 | i.def("makePerson", makePerson, factory("Person")); 41 | i.def("killPerson", killPerson, sink(1)); 42 | } 43 | -------------------------------------------------------------------------------- /examples/example6.cc: -------------------------------------------------------------------------------- 1 | // example6.cc 2 | 3 | #include "../cpptcl.h" 4 | #include 5 | 6 | using namespace std; 7 | using namespace Tcl; 8 | 9 | int main() 10 | { 11 | interpreter i; 12 | 13 | int numbers[] = {5, 7, 1, 6, 3, 9, 7}; 14 | size_t elems = sizeof(numbers) / sizeof(int); 15 | 16 | object tab; 17 | for (size_t indx = 0; indx != elems; ++indx) 18 | { 19 | tab.append(i, object(numbers[indx])); 20 | } 21 | 22 | object cmd("lsort -integer"); 23 | cmd.append(i, tab); 24 | 25 | // here, cmd contains the following: 26 | // lsort -integer {5 7 1 6 3 9 7} 27 | 28 | object result = i.eval(cmd); 29 | 30 | cout << "unsorted: "; 31 | for (size_t indx = 0; indx != elems; ++indx) 32 | { 33 | cout << numbers[indx] << ' '; 34 | } 35 | 36 | cout << "\n sorted: "; 37 | elems = result.length(i); 38 | for (size_t indx = 0; indx != elems; ++indx) 39 | { 40 | object obj(result.at(i, indx)); 41 | int val = obj.get(i); 42 | 43 | cout << val << ' '; 44 | } 45 | cout << '\n'; 46 | } 47 | -------------------------------------------------------------------------------- /examples/example7.cc: -------------------------------------------------------------------------------- 1 | // example7.cc 2 | 3 | #include "cpptcl.h" 4 | 5 | using namespace Tcl; 6 | 7 | int sumAll(object const &argv) 8 | { 9 | interpreter i(argv.get_interp(), false); 10 | 11 | int sum = 0; 12 | 13 | size_t argc = argv.length(i); 14 | for (size_t indx = 0; indx != argc; ++indx) 15 | { 16 | object o(argv.at(i, indx)); 17 | sum += o.get(i); 18 | } 19 | 20 | return sum; 21 | } 22 | 23 | CPPTCL_MODULE(Mymodule, i) 24 | { 25 | i.def("sum", sumAll, variadic()); 26 | } 27 | -------------------------------------------------------------------------------- /preproc/callbacks.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2012, Wei Song 2 | // 3 | // Permission to copy, use, modify, sell and distribute this software 4 | // is granted provided this copyright notice appears in all copies. 5 | // This software is provided "as is" without express or implied 6 | // warranty, and with no claim as to its suitability for any purpose. 7 | // 8 | 9 | // this is not a stand alone header file 10 | 11 | #define n BOOST_PP_ITERATION() 12 | 13 | #define dispatch_print(z, n, data) \ 14 | tcl_cast::from(interp, objv[BOOST_PP_INC(n)]) 15 | 16 | template 17 | class BOOST_PP_CAT(callback,n) : public callback_base 18 | { 19 | typedef R (*functor_type)(BOOST_PP_ENUM_PARAMS(n,T)); 20 | 21 | public: 22 | BOOST_PP_CAT(callback,n)(functor_type f) : f_(f) {} 23 | 24 | virtual void invoke(Tcl_Interp *interp, 25 | int objc, Tcl_Obj * CONST objv[], 26 | policies const &, ClientData) 27 | { 28 | check_params_no(objc, BOOST_PP_INC(n)); 29 | 30 | dispatch::template do_dispatch(interp, f_, 31 | BOOST_PP_ENUM(n, dispatch_print, ~)); 32 | } 33 | 34 | private: 35 | functor_type f_; 36 | }; 37 | 38 | #undef dispatch_print 39 | #undef n 40 | -------------------------------------------------------------------------------- /preproc/callbacks_cd.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2012, Wei Song 2 | // 3 | // Permission to copy, use, modify, sell and distribute this software 4 | // is granted provided this copyright notice appears in all copies. 5 | // This software is provided "as is" without express or implied 6 | // warranty, and with no claim as to its suitability for any purpose. 7 | // 8 | 9 | // this is not a stand alone header file 10 | 11 | #define n BOOST_PP_ITERATION() 12 | 13 | #define dispatch_print(z, n, data) \ 14 | tcl_cast::from(interp, objv[BOOST_PP_ADD(n,1)]) 15 | 16 | template 17 | class BOOST_PP_CAT(BOOST_PP_CAT(callback,n),_cd) : public callback_base 18 | { 19 | typedef R (*functor_type)(BOOST_PP_ENUM_PARAMS(n,T) *); 20 | 21 | public: 22 | BOOST_PP_CAT(BOOST_PP_CAT(callback,n),_cd)(functor_type f) : f_(f) {} 23 | 24 | virtual void invoke(Tcl_Interp *interp, 25 | int objc, Tcl_Obj * CONST objv[], 26 | policies const &, ClientData cd) 27 | { 28 | check_params_no(objc, n); 29 | 30 | dispatch::template do_dispatch(interp, f_, 31 | BOOST_PP_ENUM(BOOST_PP_DEC(n), dispatch_print, ~), 32 | static_cast(cd)); 33 | } 34 | 35 | private: 36 | functor_type f_; 37 | }; 38 | 39 | template 40 | class BOOST_PP_CAT(BOOST_PP_CAT(callback,n),_cd) : public callback_base 41 | { 42 | typedef object const & BOOST_PP_CAT(T,BOOST_PP_SUB(n,2)); 43 | typedef R (*functor_type)(BOOST_PP_ENUM_PARAMS(n,T) *); 44 | enum { var_start = BOOST_PP_DEC(n) }; 45 | 46 | public: 47 | BOOST_PP_CAT(BOOST_PP_CAT(callback,n),_cd)(functor_type f) : f_(f) {} 48 | 49 | virtual void invoke(Tcl_Interp *interp, 50 | int objc, Tcl_Obj * CONST objv[], 51 | policies const &pol, ClientData cd) 52 | { 53 | object mm = get_var_params(interp, objc, objv, var_start, pol); 54 | 55 | dispatch::template do_dispatch(interp, f_, 56 | BOOST_PP_ENUM(BOOST_PP_SUB(n,2), dispatch_print, ~), mm, 57 | static_cast(cd)); 58 | } 59 | 60 | private: 61 | functor_type f_; 62 | }; 63 | 64 | #undef dispatch_print 65 | #undef n 66 | -------------------------------------------------------------------------------- /preproc/callbacks_v.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2012, Wei Song 2 | // 3 | // Permission to copy, use, modify, sell and distribute this software 4 | // is granted provided this copyright notice appears in all copies. 5 | // This software is provided "as is" without express or implied 6 | // warranty, and with no claim as to its suitability for any purpose. 7 | // 8 | 9 | // this is not a stand alone header file 10 | 11 | #define n BOOST_PP_ITERATION() 12 | 13 | #define dispatch_print(z, n, data) \ 14 | tcl_cast::from(interp, objv[BOOST_PP_ADD(n,1)]) 15 | 16 | template 17 | class BOOST_PP_CAT(callback,n) : public callback_base 18 | { 19 | typedef object const & BOOST_PP_CAT(T,BOOST_PP_DEC(n)); 20 | typedef R (*functor_type)(BOOST_PP_ENUM_PARAMS(n,T)); 21 | enum { var_start = n }; 22 | 23 | public: 24 | BOOST_PP_CAT(callback,n)(functor_type f) : f_(f) {} 25 | 26 | virtual void invoke(Tcl_Interp *interp, 27 | int objc, Tcl_Obj * CONST objv[], 28 | policies const &pol, ClientData) 29 | { 30 | object mm = get_var_params(interp, objc, objv, var_start, pol); 31 | 32 | dispatch::template do_dispatch(interp, f_, 33 | BOOST_PP_ENUM(BOOST_PP_DEC(n), dispatch_print, ~), mm); 34 | } 35 | 36 | private: 37 | functor_type f_; 38 | }; 39 | 40 | #undef dispatch_print 41 | #undef n 42 | -------------------------------------------------------------------------------- /preproc/class_definer.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2012, Wei Song 2 | // 3 | // Permission to copy, use, modify, sell and distribute this software 4 | // is granted provided this copyright notice appears in all copies. 5 | // This software is provided "as is" without express or implied 6 | // warranty, and with no claim as to its suitability for any purpose. 7 | // 8 | 9 | // this is not a stand alone header file 10 | 11 | #define n BOOST_PP_ITERATION() 12 | template 13 | class_definer & def(std::string const &name, 14 | R (C::*f)(BOOST_PP_ENUM_PARAMS(n,T)), policies const &p = policies()) 15 | { 16 | ch_->register_method(name, 17 | boost::shared_ptr( 18 | new details::BOOST_PP_CAT(method,n)(f)), 19 | p); 20 | return *this; 21 | } 22 | 23 | template 24 | class_definer & def(std::string const &name, 25 | R (C::*f)(BOOST_PP_ENUM_PARAMS(n,T)) const, 26 | policies const &p = policies()) 27 | { 28 | ch_->register_method(name, 29 | boost::shared_ptr( 30 | new details::BOOST_PP_CAT(method,n)(f)), 31 | p); 32 | return *this; 33 | } 34 | #undef n 35 | -------------------------------------------------------------------------------- /preproc/interp_def.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2012, Wei Song 2 | // 3 | // Permission to copy, use, modify, sell and distribute this software 4 | // is granted provided this copyright notice appears in all copies. 5 | // This software is provided "as is" without express or implied 6 | // warranty, and with no claim as to its suitability for any purpose. 7 | // 8 | 9 | // this is not a stand alone header file 10 | 11 | #define n BOOST_PP_ITERATION() 12 | template 13 | void def(std::string const &name, R (*f)(BOOST_PP_ENUM_PARAMS(n,T)), 14 | policies const &p = policies()) 15 | { 16 | add_function(name, 17 | boost::shared_ptr( 18 | new details::BOOST_PP_CAT(callback,n)(f)), p); 19 | } 20 | 21 | // using the last arg as a client data, but must be pointer 22 | template 23 | void def(std::string const &name, R (*f)(BOOST_PP_ENUM_PARAMS(BOOST_PP_ADD(n,1),T) *), BOOST_PP_CAT(T,n) *cData, 24 | policies const &p = policies()) { 25 | add_function(name, 26 | boost::shared_ptr 27 | (new details::BOOST_PP_CAT(BOOST_PP_CAT(callback,BOOST_PP_ADD(n,1)),_cd)(f)), p, (ClientData)(cData)); 28 | } 29 | #undef n 30 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2011-2012, Wei Song 2 | # 3 | # Permission to copy, use, modify, sell and distribute this software 4 | # is granted provided this copyright notice appears in all copies. 5 | # This software is provided "as is" without express or implied 6 | # warranty, and with no claim as to its suitability for any purpose. 7 | # 8 | 9 | INCDIRS = -I. -I.. 10 | 11 | OUTPUTS = test1 test3 test4 test5 test6 test7 test8 12 | 13 | all : build test2.so test9 dotest 14 | 15 | build : $(OUTPUTS) 16 | 17 | $(OUTPUTS) : %:%.cc ../cpptcl.o 18 | $(CXX) $(INCDIRS) $(CXXFLAGS) $< ../cpptcl.o $(OBJ_LINKFLAGS) -o $@ 19 | 20 | test2.so : test2.cc ../cpptcl.o 21 | $(CXX) $(INCDIRS) $(CXXFLAGS) $< ../cpptcl.o $(SHARED_LINKFLAGS) -o $@ 22 | 23 | test9: test8.cc ../cpptcl.o 24 | $(CXX) $(INCDIRS) $(CXXFLAGS) -c test8.cc -o test8.o 25 | $(CXX) ../cpptcl.o test8.o $(OBJ_LINKFLAGS) -o $@ 26 | 27 | dotest : 28 | ./test1 29 | tclsh test2.tcl 30 | ./test3 31 | ./test4 32 | ./test5 33 | ./test6 34 | ./test7 35 | ./test8 36 | ./test9 37 | 38 | clean : 39 | -rm -f ${OUTPUTS} test2.so test8.o test9 40 | -------------------------------------------------------------------------------- /test/test1.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2012, Wei Song 2 | // Copyright (C) 2004-2006, Maciej Sobczak 3 | // 4 | // Permission to copy, use, modify, sell and distribute this software 5 | // is granted provided this copyright notice appears in all copies. 6 | // This software is provided "as is" without express or implied 7 | // warranty, and with no claim as to its suitability for any purpose. 8 | // 9 | 10 | #include "cpptcl.h" 11 | #include 12 | 13 | using namespace Tcl; 14 | 15 | static int data = 0; 16 | static interpreter gi; 17 | 18 | void fun0() {} 19 | int fun1() { return 8; } 20 | int fun2(int i) { return i + 2; } 21 | int fun3(int const &i) { return i + 2; } 22 | int fun4(std::string const &s) { return s.size(); } 23 | int fun5(char const *s) { return std::string(s).size(); } 24 | 25 | // functions use client data 26 | int fund1(int * d) { return ++(*d);} 27 | int fund2(int d0, int* d) { *d += d0; return *d;} 28 | int fund3(int d0, int d1, int* d) { *d += d0 + d1; return *d;} 29 | int fund4(int d0, int d1, int d2, 30 | int* d) { *d += d0 + d1 + d2; return *d;} 31 | int fund5(int d0, int d1, int d2, 32 | int d3, int* d) { 33 | *d += d0 + d1 + d2 + d3; return *d; 34 | } 35 | int fund6(int d0, int d1, int d2, 36 | int d3, int d4, int* d) { 37 | *d += d0 + d1 + d2 + d3 + d4; return *d; 38 | } 39 | int fund7(int d0, int d1, int d2, 40 | int d3, int d4, int d5, 41 | int* d) { 42 | *d += d0 + d1 + d2 + d3 + d4 + d5; 43 | return *d; 44 | } 45 | int fund8(int d0, int d1, int d2, 46 | int d3, int d4, int d5, 47 | int d6, int* d) { 48 | *d += d0 + d1 + d2 + d3 + d4 + d5 + d6; 49 | return *d; 50 | } 51 | int fund9(int d0, int d1, int d2, 52 | int d3, int d4, int d5, 53 | int d6, int d7, int* d) { 54 | *d += d0 + d1 + d2 + d3 + d4 + d5 + d6 + d7; 55 | return *d; 56 | } 57 | 58 | // client data with object 59 | int funod2(const object& d0, int* d) { *d += d0.get(gi); return *d;} 60 | int funod3(int d0, const object& d1, int* d) { *d += d0 + d1.get(gi); return *d;} 61 | int funod4(int d0, int d1, const object& d2, 62 | int* d) { *d += d0 + d1 + d2.get(gi); return *d;} 63 | int funod5(int d0, int d1, int d2, 64 | const object& d3, int* d) { 65 | *d += d0 + d1 + d2 + d3.get(gi); return *d; 66 | } 67 | int funod6(int d0, int d1, int d2, 68 | int d3, const object& d4, int* d) { 69 | *d += d0 + d1 + d2 + d3 + d4.get(gi); return *d; 70 | } 71 | int funod7(int d0, int d1, int d2, 72 | int d3, int d4, const object& d5, 73 | int* d) { 74 | *d += d0 + d1 + d2 + d3 + d4 + d5.get(gi); 75 | return *d; 76 | } 77 | int funod8(int d0, int d1, int d2, 78 | int d3, int d4, int d5, 79 | const object& d6, int* d) { 80 | *d += d0 + d1 + d2 + d3 + d4 + d5 + d6.get(gi); 81 | return *d; 82 | } 83 | int funod9(int d0, int d1, int d2, 84 | int d3, int d4, int d5, 85 | int d6, const object& d7, int* d) { 86 | *d += d0 + d1 + d2 + d3 + d4 + d5 + d6 + d7.get(gi); 87 | return *d; 88 | } 89 | 90 | 91 | void test1() 92 | { 93 | interpreter i; 94 | i.make_safe(); 95 | 96 | std::string s = i.eval("return \"ala ma kota\""); 97 | assert(s == "ala ma kota"); 98 | 99 | i.eval("proc myproc {} { return 7 }"); 100 | s = static_cast(i.eval("myproc")); 101 | assert(s == "7"); 102 | 103 | int ival = i.eval("myproc"); 104 | assert(ival == 7); 105 | double dval = i.eval("myproc"); 106 | assert(dval == 7.0); 107 | 108 | i.def("fun0", fun0); 109 | i.eval("fun0"); 110 | 111 | i.def("fun1", fun1); 112 | ival = i.eval("fun1"); 113 | assert(ival == 8); 114 | 115 | i.def("fun2", fun2); 116 | ival = i.eval("fun2 7"); 117 | assert(ival == 9); 118 | 119 | i.def("fun3", fun3); 120 | ival = i.eval("fun3 7"); 121 | assert(ival == 9); 122 | 123 | i.def("fun4", fun4); 124 | ival = i.eval("fun4 \"ala ma kota\""); 125 | assert(ival == 11); 126 | 127 | i.def("fun5", fun5); 128 | ival = i.eval("fun5 \"ala ma kotka\""); 129 | assert(ival == 12); 130 | 131 | try 132 | { 133 | i.eval("fun2 notaninteger"); 134 | assert(false); 135 | } 136 | catch (std::exception const &) {} 137 | 138 | // test for client data 139 | i.def("fund1", fund1, &data); 140 | i.def("fund2", fund2, &data); 141 | i.def("fund3", fund3, &data); 142 | i.def("fund4", fund4, &data); 143 | i.def("fund5", fund5, &data); 144 | i.def("fund6", fund6, &data); 145 | i.def("fund7", fund7, &data); 146 | i.def("fund8", fund8, &data); 147 | i.def("fund9", fund9, &data); 148 | i.def("funod2", funod2, &data); 149 | i.def("funod3", funod3, &data); 150 | i.def("funod4", funod4, &data); 151 | i.def("funod5", funod5, &data); 152 | i.def("funod6", funod6, &data); 153 | i.def("funod7", funod7, &data); 154 | i.def("funod8", funod8, &data); 155 | i.def("funod9", funod9, &data); 156 | 157 | int rv; 158 | rv = i.eval("fund1"); 159 | assert(rv == 1); 160 | rv = i.eval("fund2 1"); 161 | assert(rv == 2); 162 | rv = i.eval("fund3 1 1"); 163 | assert(rv == 4); 164 | rv = i.eval("fund4 1 1 1"); 165 | assert(rv == 7); 166 | rv = i.eval("fund5 1 1 1 1"); 167 | assert(rv == 11); 168 | rv = i.eval("fund6 1 1 1 1 1"); 169 | assert(rv == 16); 170 | rv = i.eval("fund7 1 1 1 1 1 1"); 171 | assert(rv == 22); 172 | rv = i.eval("fund8 1 1 1 1 1 1 1"); 173 | assert(rv == 29); 174 | rv = i.eval("fund9 1 1 1 1 1 1 1 1"); 175 | assert(rv == 37); 176 | rv = i.eval("funod2 1"); 177 | assert(rv == 38); 178 | rv = i.eval("funod3 1 1"); 179 | assert(rv == 40); 180 | rv = i.eval("funod4 1 1 1"); 181 | assert(rv == 43); 182 | rv = i.eval("funod5 1 1 1 1"); 183 | assert(rv == 47); 184 | rv = i.eval("funod6 1 1 1 1 1"); 185 | assert(rv == 52); 186 | rv = i.eval("funod7 1 1 1 1 1 1"); 187 | assert(rv == 58); 188 | rv = i.eval("funod8 1 1 1 1 1 1 1"); 189 | assert(rv == 65); 190 | rv = i.eval("funod9 1 1 1 1 1 1 1 1"); 191 | assert(rv == 73); 192 | 193 | } 194 | 195 | int main() 196 | { 197 | try 198 | { 199 | test1(); 200 | } 201 | catch (std::exception const &e) 202 | { 203 | std::cerr << "Error: " << e.what() << '\n'; 204 | } 205 | } 206 | -------------------------------------------------------------------------------- /test/test2.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2004-2006, Maciej Sobczak 3 | // 4 | // Permission to copy, use, modify, sell and distribute this software 5 | // is granted provided this copyright notice appears in all copies. 6 | // This software is provided "as is" without express or implied 7 | // warranty, and with no claim as to its suitability for any purpose. 8 | // 9 | 10 | #include "cpptcl.h" 11 | #include 12 | #include 13 | 14 | 15 | void fun0() 16 | { 17 | std::cout << "fun0\n"; 18 | } 19 | 20 | int fun1() 21 | { 22 | return 7; 23 | } 24 | 25 | std::string fun2() 26 | { 27 | return "Ala ma kota"; 28 | } 29 | 30 | int add(int a, int b) 31 | { 32 | return a + b; 33 | } 34 | 35 | int mystrlen(std::string const &s) 36 | { 37 | return s.size(); 38 | } 39 | 40 | CPPTCL_MODULE(Test, i) 41 | { 42 | i.def("fun0", fun0); 43 | i.def("fun1", fun1); 44 | i.def("fun2", fun2); 45 | i.def("add", add); 46 | i.def("mystrlen", mystrlen); 47 | } 48 | -------------------------------------------------------------------------------- /test/test2.tcl: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2004-2006, Maciej Sobczak 3 | # 4 | # Permission to copy, use, modify, sell and distribute this software 5 | # is granted provided this copyright notice appears in all copies. 6 | # This software is provided "as is" without express or implied 7 | # warranty, and with no claim as to its suitability for any purpose. 8 | # 9 | 10 | load ./test2.so 11 | 12 | set i [fun1] 13 | if {$i != 7} { error "Assertion failed" } 14 | 15 | set s [fun2] 16 | if {$s != "Ala ma kota"} { error "Assertion failed" } 17 | 18 | set i [add 4 5] 19 | if {$i != 9} { error "Assertion failed" } 20 | 21 | set i [mystrlen $s] 22 | if {$i != [string length $s]} { error "Assertion failed" } 23 | -------------------------------------------------------------------------------- /test/test3.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2004-2006, Maciej Sobczak 3 | // 4 | // Permission to copy, use, modify, sell and distribute this software 5 | // is granted provided this copyright notice appears in all copies. 6 | // This software is provided "as is" without express or implied 7 | // warranty, and with no claim as to its suitability for any purpose. 8 | // 9 | 10 | #include "cpptcl.h" 11 | #include 12 | #include 13 | 14 | using namespace Tcl; 15 | 16 | 17 | std::string did; 18 | int objNum = 0; 19 | 20 | class C 21 | { 22 | public: 23 | C() : num_(++objNum) { did = "C::C()"; } 24 | C(int i, std::string const &s = std::string("default")) 25 | : num_(++objNum) 26 | { 27 | std::ostringstream ss; 28 | ss << "C::C(" << i << ", " << s << ")"; 29 | did = ss.str(); 30 | } 31 | 32 | ~C() 33 | { 34 | std::ostringstream ss; 35 | ss << "C::~C() on " << num_; 36 | did = ss.str(); 37 | --objNum; 38 | } 39 | 40 | void fun0() 41 | { 42 | std::ostringstream ss; 43 | ss << "C::fun0() on " << num_; 44 | did = ss.str(); 45 | } 46 | 47 | int fun1(int a, int b) 48 | { 49 | std::ostringstream ss; 50 | ss << "adding on " << num_ << ": " << a << " + " << b; 51 | did = ss.str(); 52 | 53 | return a + b; 54 | } 55 | 56 | private: 57 | int num_; 58 | }; 59 | 60 | C * source() 61 | { 62 | return new C; 63 | } 64 | 65 | void use(C *p) 66 | { 67 | p->fun0(); 68 | } 69 | 70 | void sinkFun(C *p) 71 | { 72 | delete p; 73 | } 74 | 75 | void test1() 76 | { 77 | interpreter i; 78 | 79 | i.class_("C", init()); 80 | i.class_("C2", init()); 81 | i.class_("C3", init<>()); 82 | i.class_("C4") 83 | .def("add", &C::fun1); 84 | 85 | i.def("source", source, factory("C4")); 86 | i.def("use", use); 87 | i.def("sink", sinkFun, sink(1)); 88 | 89 | i.eval("set p [source]"); 90 | assert(did == "C::C()"); 91 | assert(objNum == 1); 92 | 93 | int res = i.eval("$p add 2 3"); 94 | assert(res == 5); 95 | assert(did == "adding on 1: 2 + 3"); 96 | 97 | i.eval("use $p"); 98 | assert(did == "C::fun0() on 1"); 99 | 100 | i.eval("sink $p"); 101 | assert(did == "C::~C() on 1"); 102 | assert(objNum == 0); 103 | 104 | // now, the object and its command should not exist 105 | try 106 | { 107 | // exception expected 108 | i.eval("$p -delete"); 109 | assert(false); 110 | } 111 | catch (...) {} 112 | 113 | i.eval("set p [C 7 \"Ala ma kota\"]"); 114 | assert(did == "C::C(7, Ala ma kota)"); 115 | assert(objNum == 1); 116 | 117 | i.eval("use $p"); 118 | assert(did == "C::fun0() on 1"); 119 | 120 | i.eval("set p2 [C2 7]"); 121 | assert(did == "C::C(7, default)"); 122 | assert(objNum == 2); 123 | 124 | i.eval("use $p2"); 125 | assert(did == "C::fun0() on 2"); 126 | 127 | i.eval("set p3 [C3]"); 128 | assert(objNum == 3); 129 | 130 | i.eval("use $p3"); 131 | assert(did == "C::fun0() on 3"); 132 | 133 | i.eval("set p4 [C4]"); 134 | assert(objNum == 4); 135 | 136 | i.eval("use $p4"); 137 | assert(did == "C::fun0() on 4"); 138 | 139 | res = i.eval("$p4 add 3 4"); 140 | assert(res == 7); 141 | assert(did == "adding on 4: 3 + 4"); 142 | 143 | try 144 | { 145 | // exception expected 146 | i.eval("$p4 add noint noint"); 147 | assert(false); 148 | } 149 | catch (...) {} 150 | 151 | i.eval("$p -delete"); 152 | assert(did == "C::~C() on 1"); 153 | assert(objNum == 3); 154 | 155 | i.eval("$p2 -delete"); 156 | assert(did == "C::~C() on 2"); 157 | assert(objNum == 2); 158 | 159 | i.eval("$p3 -delete"); 160 | assert(did == "C::~C() on 3"); 161 | assert(objNum == 1); 162 | 163 | i.eval("$p4 -delete"); 164 | assert(did == "C::~C() on 4"); 165 | assert(objNum == 0); 166 | } 167 | 168 | int main() 169 | { 170 | try 171 | { 172 | test1(); 173 | } 174 | catch (std::exception const &e) 175 | { 176 | std::cerr << "Error: " << e.what() << '\n'; 177 | } 178 | } 179 | -------------------------------------------------------------------------------- /test/test4.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2004-2006, Maciej Sobczak 3 | // 4 | // Permission to copy, use, modify, sell and distribute this software 5 | // is granted provided this copyright notice appears in all copies. 6 | // This software is provided "as is" without express or implied 7 | // warranty, and with no claim as to its suitability for any purpose. 8 | // 9 | 10 | #include "../cpptcl.h" 11 | #include 12 | #include 13 | #include 14 | 15 | using namespace Tcl; 16 | 17 | 18 | object fun(object const &o) 19 | { 20 | Tcl_Interp *interp = o.get_interp(); 21 | interpreter i(interp, false); 22 | 23 | return object(static_cast(o.length(i))); 24 | } 25 | 26 | void test1() 27 | { 28 | char buf[] = {1, 2, 3, 4}; 29 | interpreter i; 30 | 31 | { 32 | object o(true); 33 | assert(o.get(i) == true); 34 | assert(object(o).get(i) == true); 35 | o = false; 36 | assert(o.get(i) == false); 37 | assert(object(o).get(i) == false); 38 | 39 | o = 123; 40 | assert(o.get(i) == 123); 41 | } 42 | { 43 | object o(buf, 4); 44 | size_t size; 45 | char const *b = o.get(size); 46 | assert(size == 4); 47 | assert(std::memcmp(b, buf, 4) == 0); 48 | o.resize(2); 49 | b = o.get(size); 50 | assert(size == 2); 51 | assert(memcmp(b, buf, 2) == 0); 52 | 53 | object o2(o); 54 | b = o2.get(size); 55 | assert(size == 2); 56 | assert(memcmp(b, buf, 2) == 0); 57 | 58 | o = 123; 59 | assert(o.get(i) == 123); 60 | } 61 | { 62 | object o(3.14); 63 | assert(std::fabs(o.get(i) - 3.14) < 0.001); 64 | object o2(o); 65 | assert(std::fabs(o2.get(i) - 3.14) < 0.001); 66 | 67 | o = "Ala ma kota"; 68 | assert(std::string(o.get()) == "Ala ma kota"); 69 | } 70 | { 71 | object o(1234); 72 | assert(o.get(i) == 1234); 73 | object o2(o); 74 | assert(o2.get(i) == 1234); 75 | 76 | o = 123; 77 | assert(o.get(i) == 123); 78 | } 79 | { 80 | object o(1234L); 81 | assert(o.get(i) == 1234L); 82 | object o2(o); 83 | assert(o2.get(i) == 1234L); 84 | 85 | o = 123; 86 | assert(o.get(i) == 123); 87 | } 88 | { 89 | char s[] = "Ala ma kota"; 90 | object o(s); 91 | assert(std::string(o.get()) == s); 92 | assert(std::string(o.get(i)) == s); 93 | assert(o.get(i) == s); 94 | object o2(o); 95 | assert(std::string(o2.get()) == s); 96 | assert(std::string(o2.get(i)) == s); 97 | assert(o2.get(i) == s); 98 | 99 | o = 123; 100 | assert(o.get(i) == 123); 101 | } 102 | { 103 | std::string s = "Ala ma kota"; 104 | object o(s); 105 | assert(o.get(i) == s); 106 | object o2(o); 107 | assert(o2.get(i) == s); 108 | 109 | o = 123; 110 | assert(o.get(i) == 123); 111 | } 112 | { 113 | object o1(123); 114 | object o2(321); 115 | o1.swap(o2); 116 | assert(o1.get(i) == 321); 117 | assert(o2.get(i) == 123); 118 | } 119 | { 120 | object o(123); 121 | assert(o.length(i) == 1); 122 | o = "Ala ma kota"; 123 | assert(o.length(i) == 3); 124 | assert(o.at(i, 1).get(i) == "ma"); 125 | } 126 | { 127 | object o("Ala ma kota"); 128 | o.append(i, object("na")); 129 | o.append(i, object("punkcie")); 130 | o.append(i, object("psa")); 131 | assert(o.length(i) == 6); 132 | assert(o.get(i) == "Ala ma kota na punkcie psa"); 133 | o.replace(i, 2, 1, object("hopla")); 134 | assert(o.length(i) == 6); 135 | assert(o.get(i) == "Ala ma hopla na punkcie psa"); 136 | } 137 | { 138 | object o = i.eval("set i 17"); 139 | assert(o.get(i) == 17); 140 | } 141 | { 142 | object o("set i 18"); 143 | int val = i.eval(o); 144 | assert(val == 18); 145 | } 146 | { 147 | object o1("malego kota"); 148 | object o2("ma"); o2.append(i, o1); // o2=="ma {malego kota}" 149 | object o3("Ala"); o3.append(i, o2); // o3=="Ala {ma {malego kota}}" 150 | object o4("list"); 151 | object o5("set"); 152 | 153 | std::vector v; 154 | v.push_back(o5); 155 | v.push_back(o4); 156 | v.push_back(o3); 157 | i.eval(v.begin(), v.end()); // "set list {Ala {ma {malego kota}}}" 158 | int ret = i.eval("llength $list"); 159 | assert(ret == 2); 160 | std::string s = i.eval("lindex $list 0"); 161 | assert(s == "Ala"); 162 | s = static_cast(i.eval("lindex $list 1")); 163 | assert(s == "ma {malego kota}"); 164 | s = static_cast( 165 | i.eval("lindex [lindex [lindex $list 1] 1] 0")); 166 | assert(s == "malego"); 167 | } 168 | } 169 | 170 | void test2() 171 | { 172 | interpreter i; 173 | i.def("fun", fun); 174 | 175 | object in("Ala ma kota"); 176 | object cmd("fun"); 177 | cmd.append(i, in); 178 | int ret = i.eval(cmd); 179 | assert(ret == 3); 180 | } 181 | 182 | int main() 183 | { 184 | try 185 | { 186 | test1(); 187 | test2(); 188 | } 189 | catch (std::exception const &e) 190 | { 191 | std::cerr << "Error: " << e.what() << '\n'; 192 | } 193 | } 194 | -------------------------------------------------------------------------------- /test/test5.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2004-2006, Maciej Sobczak 3 | // 4 | // Permission to copy, use, modify, sell and distribute this software 5 | // is granted provided this copyright notice appears in all copies. 6 | // This software is provided "as is" without express or implied 7 | // warranty, and with no claim as to its suitability for any purpose. 8 | // 9 | 10 | #include "../cpptcl.h" 11 | #include 12 | 13 | using namespace Tcl; 14 | 15 | 16 | int fun() { return 7; } 17 | 18 | void test1() 19 | { 20 | interpreter i; 21 | 22 | i.eval("namespace eval NS {}"); 23 | i.def("NS::fun", fun); 24 | 25 | int ret = i.eval("NS::fun"); 26 | assert(ret == 7); 27 | } 28 | 29 | void test2() 30 | { 31 | interpreter i1, i2; 32 | 33 | i1.def("fun", fun); 34 | i2.create_alias("fun2", i1, "fun"); 35 | 36 | int ret = i2.eval("fun2"); 37 | assert(ret == 7); 38 | } 39 | 40 | int main() 41 | { 42 | try 43 | { 44 | test1(); 45 | test2(); 46 | } 47 | catch (std::exception const &e) 48 | { 49 | std::cerr << "Error: " << e.what() << '\n'; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /test/test6.cc: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) 2004-2006, Maciej Sobczak 3 | // 4 | // Permission to copy, use, modify, sell and distribute this software 5 | // is granted provided this copyright notice appears in all copies. 6 | // This software is provided "as is" without express or implied 7 | // warranty, and with no claim as to its suitability for any purpose. 8 | // 9 | 10 | #include "../cpptcl.h" 11 | #include 12 | 13 | using namespace Tcl; 14 | 15 | 16 | int funv1(int, object const &o) 17 | { 18 | interpreter i(o.get_interp(), false); 19 | return o.length(i); 20 | } 21 | 22 | int funv2(int a, int b, object const &o) 23 | { 24 | assert(a == 1); 25 | assert(b == 2); 26 | 27 | interpreter i(o.get_interp(), false); 28 | assert(o.get(i) == 3); 29 | 30 | return o.length(i); 31 | } 32 | 33 | int funv3(int a, int b, object const &o) 34 | { 35 | assert(a == 1); 36 | assert(b == 2); 37 | 38 | interpreter i(o.get_interp(), false); 39 | assert(o.length(i) == 3); 40 | assert(o.at(i, 0).get(i) == 3); 41 | assert(o.at(i, 1).get(i) == 4); 42 | assert(o.at(i, 2).get(i) == 5); 43 | 44 | return o.length(i); 45 | } 46 | 47 | class C 48 | { 49 | public: 50 | C() {} 51 | 52 | C(int, object const &o) 53 | { 54 | interpreter i(o.get_interp(), false); 55 | len_ = o.length(i); 56 | } 57 | 58 | int getLen() const { return len_; } 59 | 60 | int len(int, object const &o) 61 | { 62 | interpreter i(o.get_interp(), false); 63 | return o.length(i); 64 | } 65 | 66 | int lenc(int, object const &o) const 67 | { 68 | interpreter i(o.get_interp(), false); 69 | return o.length(i); 70 | } 71 | 72 | private: 73 | int len_; 74 | }; 75 | 76 | void test1() 77 | { 78 | interpreter i; 79 | std::stringstream ss("set i 5\nset i"); 80 | 81 | int ret = i.eval(ss); 82 | assert(ret == 5); 83 | } 84 | 85 | void test2() 86 | { 87 | interpreter i; 88 | i.def("fun1", funv1); 89 | i.def("fun1v", funv1, variadic()); 90 | 91 | int ret = i.eval("fun1 1 2 3 4"); 92 | assert(ret == 1); 93 | 94 | try 95 | { 96 | i.eval("fun1 1"); 97 | assert(false); 98 | } 99 | catch (tcl_error const &e) 100 | { 101 | assert(e.what() == std::string("Too few arguments.")); 102 | } 103 | 104 | ret = i.eval("fun1v 1 2 3 4"); 105 | assert(ret == 3); 106 | 107 | ret = i.eval("fun1v 1"); 108 | assert(ret == 0); 109 | 110 | i.def("fun2", funv2); 111 | ret = i.eval("fun2 1 2 3 4 5"); 112 | assert(ret == 1); 113 | 114 | i.def("fun3", funv3, variadic()); 115 | ret = i.eval("fun3 1 2 3 4 5"); 116 | assert(ret == 3); 117 | 118 | 119 | i.class_("C", init()) 120 | .def("len", &C::getLen); 121 | 122 | ret = i.eval( 123 | "set obj [C 1 2 3 4]\n" 124 | "set len [$obj len]\n" 125 | "$obj -delete\n" 126 | "set len" 127 | ); 128 | assert(ret == 1); 129 | 130 | i.class_("Cv", init(), variadic()) 131 | .def("len", &C::getLen); 132 | 133 | ret = i.eval( 134 | "set obj [Cv 1 2 3 4]\n" 135 | "set len [$obj len]\n" 136 | "$obj -delete\n" 137 | "set len" 138 | ); 139 | assert(ret == 3); 140 | 141 | ret = i.eval( 142 | "set obj [Cv 1]\n" 143 | "set len [$obj len]\n" 144 | "$obj -delete\n" 145 | "set len" 146 | ); 147 | assert(ret == 0); 148 | 149 | i.class_("C2") 150 | .def("len", &C::len) 151 | .def("lenv", &C::len, variadic()) 152 | .def("lenc", &C::len) 153 | .def("lencv", &C::len, variadic()); 154 | 155 | i.eval("set obj [C2]"); 156 | 157 | ret = i.eval("$obj len 1 2 3 4"); 158 | assert(ret == 1); 159 | 160 | ret = i.eval("$obj lenv 1 2 3 4"); 161 | assert(ret == 3); 162 | 163 | ret = i.eval("$obj lenv 1"); 164 | assert(ret == 0); 165 | 166 | ret = i.eval("$obj lenc 1 2 3 4"); 167 | assert(ret == 1); 168 | 169 | ret = i.eval("$obj lencv 1 2 3 4"); 170 | assert(ret == 3); 171 | 172 | i.eval("$obj -delete"); 173 | } 174 | 175 | int main() 176 | { 177 | try 178 | { 179 | test1(); 180 | test2(); 181 | } 182 | catch (std::exception const &e) 183 | { 184 | std::cerr << "Error: " << e.what() << '\n'; 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /test/test7.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2012, Wei Song 2 | // 3 | // Permission to copy, use, modify, sell and distribute this software 4 | // is granted provided this copyright notice appears in all copies. 5 | // This software is provided "as is" without express or implied 6 | // warranty, and with no claim as to its suitability for any purpose. 7 | // 8 | 9 | #include "cpptcl.h" 10 | 11 | static int gdata = 2; // a global data 12 | 13 | void fun(int d, int * gd) { // gd comes from environment 14 | *gd += d; 15 | } 16 | 17 | int main() { 18 | Tcl::interpreter i; 19 | 20 | i.def("fun", fun, &gdata); // send gdata to the Tcl fun 21 | 22 | i.eval("fun 10"); // only one argument is passed by Tcl command 23 | assert(gdata == 12); // check the global data is changed 24 | 25 | return 0; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /test/test8.cc: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2011-2012, Wei Song 2 | // 3 | // Permission to copy, use, modify, sell and distribute this software 4 | // is granted provided this copyright notice appears in all copies. 5 | // This software is provided "as is" without express or implied 6 | // warranty, and with no claim as to its suitability for any purpose. 7 | // 8 | 9 | #include "cpptcl.h" 10 | #include 11 | 12 | using std::cout; 13 | using std::endl; 14 | using std::string; 15 | using namespace Tcl; 16 | 17 | interpreter i; 18 | 19 | bool read_trace_bool(const bool& v, void *) { 20 | return !v; 21 | } 22 | 23 | bool write_trace_bool(const bool& v, void *) { 24 | return !v; 25 | } 26 | 27 | int read_trace_int(const int& v, int * cd) { 28 | *cd = v; 29 | return v+1; 30 | } 31 | 32 | int write_trace_int(const int& v, int * cd) { 33 | *cd = v; 34 | return v-1; 35 | } 36 | 37 | void test_read_trace() { 38 | //interpreter i; 39 | int env = 10; 40 | i.def_read_trace("vbool", "read_trace_bool", read_trace_bool); // add trace 41 | i.def_read_trace("vint", "read_trace_int", read_trace_int, &env); 42 | i.eval("set vbool 1"); // set variable 43 | string rv = i.eval("set vbool"); // read it 44 | assert(rv == "0"); 45 | i.eval("set vint 17"); 46 | string rv2 = i.eval("set vint"); 47 | assert(rv2 == "18" && env == 17); 48 | i.undef_read_trace("vbool"); // untrace with var name only 49 | i.undef_read_trace("vint", "read_trace_int"); // untrace with name 50 | i.eval("set vbool"); // error if not untraced 51 | i.eval("set vint"); // error if not untraced 52 | } 53 | 54 | void test_write_trace() { 55 | interpreter i; 56 | int env = 10; 57 | i.def_write_trace("vbool", "write_trace_bool", write_trace_bool); // add trace 58 | i.def_write_trace("vint", "write_trace_int", write_trace_int, &env); 59 | string rv = i.eval("set vbool 1"); // set variable 60 | assert(rv == "0"); 61 | string rv2 = i.eval("set vint 17"); 62 | assert(rv2 == "16" && env == 17); 63 | i.undef_write_trace("vbool"); // untrace with var name only 64 | i.undef_write_trace("vint", "write_trace_int"); // untrace with name 65 | i.eval("set vbool 1"); // error if not untraced 66 | i.eval("set vint 19"); // error if not untraced 67 | } 68 | 69 | void test_read_and_write_trace() { 70 | //interpreter i; 71 | int env = 10; 72 | i.def_read_trace("vbool", "read_trace_bool", read_trace_bool); // add trace 73 | i.def_read_trace("vint", "read_trace_int", read_trace_int, &env); 74 | i.def_write_trace("vbool", "write_trace_bool", write_trace_bool); // add trace 75 | i.def_write_trace("vint", "write_trace_int", write_trace_int, &env); 76 | string rv = i.eval("set vbool 1"); // set variable 77 | assert(rv == "0"); 78 | string rv1 = i.eval("set vbool"); // read it 79 | assert(rv1 == "1"); 80 | string rv2 = i.eval("set vint 17"); 81 | assert(rv2 == "16" && env == 17); 82 | string rv3 = i.eval("set vint"); 83 | assert(rv3 == "17" && env == 16); 84 | i.undef_all_trace("vbool"); // untrace all 85 | i.undef_all_trace("vint"); 86 | i.eval("set vbool 1"); // error if not untraced 87 | i.eval("set vbool"); // error if not untraced 88 | i.eval("set vint 17"); // error if not untraced 89 | i.eval("set vint"); // error if not untraced 90 | } 91 | 92 | int main() { 93 | try { 94 | test_read_trace(); 95 | } catch (std::exception const &e) { 96 | std::cerr << "Error: " << e.what() << '\n'; 97 | } 98 | 99 | try { 100 | test_write_trace(); 101 | } catch (std::exception const &e) { 102 | std::cerr << "Error: " << e.what() << '\n'; 103 | } 104 | 105 | try { 106 | test_read_and_write_trace(); 107 | } catch (std::exception const &e) { 108 | std::cerr << "Error: " << e.what() << '\n'; 109 | } 110 | 111 | return 0; 112 | } 113 | --------------------------------------------------------------------------------