00001 /** @file tcl/pkg.h tcl package class, holds a set of commands, wraps 00002 calls to Tcl_PkgProvide(), etc. */ 00003 00004 /////////////////////////////////////////////////////////////////////// 00005 // 00006 // Copyright (c) 1999-2004 California Institute of Technology 00007 // Copyright (c) 2004-2007 University of Southern California 00008 // Rob Peters <rjpeters at usc dot edu> 00009 // 00010 // created: Tue Jun 15 12:33:59 1999 00011 // commit: $Id: pkg.h 11876 2009-10-22 15:53:06Z icore $ 00012 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/tcl/pkg.h $ 00013 // 00014 // -------------------------------------------------------------------- 00015 // 00016 // This file is part of GroovX 00017 // [http://ilab.usc.edu/rjpeters/groovx/] 00018 // 00019 // GroovX is free software; you can redistribute it and/or modify it 00020 // under the terms of the GNU General Public License as published by 00021 // the Free Software Foundation; either version 2 of the License, or 00022 // (at your option) any later version. 00023 // 00024 // GroovX is distributed in the hope that it will be useful, but 00025 // WITHOUT ANY WARRANTY; without even the implied warranty of 00026 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00027 // General Public License for more details. 00028 // 00029 // You should have received a copy of the GNU General Public License 00030 // along with GroovX; if not, write to the Free Software Foundation, 00031 // Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. 00032 // 00033 /////////////////////////////////////////////////////////////////////// 00034 00035 #ifndef GROOVX_TCL_PKG_H_UTC20050628162421_DEFINED 00036 #define GROOVX_TCL_PKG_H_UTC20050628162421_DEFINED 00037 00038 #include "tcl/makecmd.h" 00039 00040 #include "rutz/fileposition.h" 00041 00042 struct Tcl_Interp; 00043 00044 namespace rutz 00045 { 00046 struct file_pos; 00047 } 00048 00049 namespace tcl 00050 { 00051 class command; 00052 class interpreter; 00053 class pkg; 00054 00055 const int NO_EXPORT = 1 << 0; 00056 } 00057 00058 /////////////////////////////////////////////////////////////////////// 00059 // 00060 // tcl::pkg class definition 00061 // 00062 /////////////////////////////////////////////////////////////////////// 00063 00064 /////////////////////////////////////////////////////////////////////// 00065 /** 00066 00067 \c tcl::pkg is a class more managing groups of related \c 00068 tcl::command's. It provides several facilities: 00069 00070 -- stores a list of \c tcl::command's, and ensures that these are 00071 properly destroyed upon exit from Tcl 00072 00073 -- ensures that the package is provided to Tcl so that other 00074 packages can query for its presence 00075 00076 -- provides a set of functions to define Tcl commands from C++ 00077 functors 00078 00079 **/ 00080 /////////////////////////////////////////////////////////////////////// 00081 00082 class tcl::pkg 00083 { 00084 private: 00085 /// Private constructor. 00086 /** Clients should use the PKG_CREATE macro instead. */ 00087 pkg(Tcl_Interp* interp, const char* name, const char* version); 00088 00089 /// Destructor destroys all \c tcl::command's owned by the package. 00090 ~pkg() throw(); 00091 00092 public: 00093 static const int STATUS_OK; 00094 static const int STATUS_ERR; 00095 00096 /// Don't call this directly! Use the PKG_CREATE macro instead. 00097 static pkg* create_in_macro(Tcl_Interp* interp, 00098 const char* name, const char* version) 00099 { 00100 return new pkg(interp, name, version); 00101 } 00102 00103 typedef void (exit_callback)(); 00104 00105 /// Specify a function to be called when the package is destroyed. 00106 /** (Package destruction typically occurs at application exit, when 00107 the Tcl interpreter and all associated objects are 00108 destroyed.) */ 00109 void on_exit(exit_callback* callback); 00110 00111 /// Looks up the tcl::pkg associated with pkgname, and destroys it. 00112 /** This is intended to be called from pkg_Unload procedures called 00113 by Tcl when a dynamic library is unloaded. The return value can 00114 be returned as the return value of the pkg_Unload procedure; it 00115 will be TCL_OK (1) if the tcl::pkg was successfully found and 00116 destroyed and TCL_ERROR (0) otherwise. */ 00117 static int destroy_on_unload(Tcl_Interp* interp, const char* pkgname); 00118 00119 /// Find a package given its name and version. 00120 /** If the package is not already loaded, this function will attempt 00121 to "require" the package. If a null pointer is passed to version 00122 (the default), then any version will be acceptable. If no 00123 suitable package cannot be found or loaded, a null pointer will 00124 be returned. */ 00125 static pkg* lookup(tcl::interpreter& interp, 00126 const char* name, const char* version = 0) throw(); 00127 00128 /** Returns a Tcl status code indicating whether the package 00129 initialization was successful. */ 00130 int init_status() const throw(); 00131 00132 /// Mark the package as having failed its initialization. 00133 void set_init_status_error() throw(); 00134 00135 /// Returns the Tcl interpreter that was passed to the constructor. 00136 tcl::interpreter& interp() throw(); 00137 00138 /// Trap a live exception, and leave a message in the Tcl_Interp's result. 00139 void handle_live_exception(const rutz::file_pos& pos) throw(); 00140 00141 /// Returns the package's "namespace name". 00142 /** Note that the "namespace name" will be the same as the "package 00143 name" except possibly for capitalization. The "namespace name" 00144 is the name of the namespace that is used as the default prefix 00145 all commands contained in the package. */ 00146 const char* namesp_name() throw(); 00147 00148 /// Return the package's "package name". 00149 /** Note that the "package name" will be the same as the "namespace 00150 name" except possibly for capitalization. The "package name" is 00151 the name that is passed to Tcl_PkgProvide() and 00152 Tcl_PkgProvide(), and has a well-defined capitalization scheme: 00153 first character uppercase, all remaining letters lowercase. */ 00154 const char* pkg_name() const throw(); 00155 00156 /// Returns the package version string. 00157 const char* version() const throw(); 00158 00159 /// Export commands into a different namespace. 00160 /** Causes all of our package's currently defined commands and 00161 procedures to be imported into the specified other namespace. If 00162 pattern is different from the default value of "*", then only 00163 commands whose names match pattern according to glob rules will 00164 be aliased into the other namespace. */ 00165 void namesp_alias(const char* namesp, const char* pattern = "*"); 00166 00167 /// Import commands from a different namespace. 00168 /** Import all of the commands and procedures defined in the 00169 specified namespace into our own package namespace. If pattern 00170 is different from the default value of "*", then only commands 00171 whose names match pattern according to glob rules will be 00172 imported into our own package namespace. */ 00173 void inherit_namesp(const char* namesp, const char* pattern = "*"); 00174 00175 /// Import all commands and procedures defined in the named pkg. 00176 /** If the named pkg has not yet been loaded, this function will 00177 attempt to load it via loookup(). If a null pointer is passed to 00178 version (the default), then any version will be acceptable. */ 00179 void inherit_pkg(const char* name, const char* version = 0); 00180 00181 /// Evaluates \a script using the package's \c Tcl_Interp. 00182 void eval(const char* script); 00183 00184 /// Links the \a var with the Tcl variable \a var_name. 00185 void link_var(const char* var_name, int& var); 00186 00187 /// Links \a var with the Tcl variable \a var_name. 00188 void link_var(const char* var_name, double& var); 00189 00190 /// Links a copy of \a var with the Tcl variable \a var_name. 00191 /** The Tcl variable will be read-only.*/ 00192 void link_var_copy(const char* var_name, int var); 00193 00194 /// Links a copy of \a var with the Tcl variable \a var_name. 00195 /** The Tcl variable will be read-only.*/ 00196 void link_var_copy(const char* var_name, double var); 00197 00198 /// Links \a var with the Tcl variable \a var_name. 00199 /** The Tcl variable will be read_only. */ 00200 void link_var_const(const char* var_name, int& var); 00201 00202 ///Links \a var with the Tcl variable \a var_name. 00203 /** The Tcl variable will be read_only. */ 00204 void link_var_const(const char* var_name, double& var); 00205 00206 00207 template <class Func> 00208 inline void def(const char* cmd_name, const char* usage, Func f, 00209 const rutz::file_pos& src_pos, int flags = 0) 00210 { 00211 make_command(interp(), f, make_pkg_cmd_name(cmd_name, flags), 00212 usage, src_pos); 00213 } 00214 00215 template <class Func> 00216 inline void def_vec(const char* cmd_name, const char* usage, Func f, 00217 unsigned int keyarg /*default is 1*/, 00218 const rutz::file_pos& src_pos, int flags = 0) 00219 { 00220 make_vec_command(interp(), f, make_pkg_cmd_name(cmd_name, flags), 00221 usage, keyarg, src_pos); 00222 } 00223 00224 template <class Func> 00225 inline void def_raw(const char* cmd_name, const arg_spec& spec, 00226 const char* usage, Func f, 00227 const rutz::file_pos& src_pos, int flags = 0) 00228 { 00229 make_generic_command(interp(), f, make_pkg_cmd_name(cmd_name, flags), 00230 usage, spec, src_pos); 00231 } 00232 00233 template <class Func> 00234 inline void def_vec_raw(const char* cmd_name, const arg_spec& spec, 00235 const char* usage, Func f, 00236 unsigned int keyarg /*default is 1*/, 00237 const rutz::file_pos& src_pos, int flags = 0) 00238 { 00239 make_generic_vec_command(interp(), f, make_pkg_cmd_name(cmd_name, flags), 00240 usage, spec, keyarg, src_pos); 00241 } 00242 00243 template <class C> 00244 void def_action(const char* cmd_name, void (C::* action_func) (), 00245 const rutz::file_pos& src_pos, int flags = 0) 00246 { 00247 def_vec( cmd_name, action_usage, action_func, 1, src_pos, flags ); 00248 } 00249 00250 template <class C> 00251 void def_action(const char* cmd_name, void (C::* action_func) () const, 00252 const rutz::file_pos& src_pos, int flags = 0) 00253 { 00254 def_vec( cmd_name, action_usage, action_func, 1, src_pos, flags ); 00255 } 00256 00257 template <class C, class T> 00258 void def_getter(const char* cmd_name, T (C::* getter_func) () const, 00259 const rutz::file_pos& src_pos, int flags = 0) 00260 { 00261 def_vec( cmd_name, getter_usage, getter_func, 1, src_pos, flags ); 00262 } 00263 00264 template <class C, class T> 00265 void def_setter(const char* cmd_name, void (C::* setter_func) (T), 00266 const rutz::file_pos& src_pos, int flags = 0) 00267 { 00268 def_vec( cmd_name, setter_usage, setter_func, 1, src_pos, flags ); 00269 } 00270 00271 template <class C, class T> 00272 void def_get_set(const char* cmd_name, 00273 T (C::* getter_func) () const, 00274 void (C::* setter_func) (T), 00275 const rutz::file_pos& src_pos, int flags = 0) 00276 { 00277 def_getter( cmd_name, getter_func, src_pos, flags ); 00278 def_setter( cmd_name, setter_func, src_pos, flags ); 00279 } 00280 00281 /// Control whether packages should be verbose as they start up. 00282 static void verbose_init(bool verbose) throw(); 00283 00284 /// Called just prior to returning from the *_Init function. 00285 /** If the package's status is OK, then this does the relevant 00286 Tcl_PkgProvide and returns TCL_OK. Otherwise, it returns 00287 TCL_ERROR. */ 00288 int finish_init() throw(); 00289 00290 private: 00291 pkg(const pkg&); // not implemented 00292 pkg& operator=(const pkg&); // not implemented 00293 00294 /** Returns a namespace'd command name in the form of 00295 pkg_name::cmd_name. The result of this function is valid only 00296 until the next time it is called, so callers should make a copy 00297 of the result. This function also has the side effect of setting 00298 up a Tcl namespace export pattern for the named command, if 00299 flags doesn't include NO_EXPORT. */ 00300 const char* make_pkg_cmd_name(const char* cmd_name, int flags); 00301 00302 static const char* const action_usage; 00303 static const char* const getter_usage; 00304 static const char* const setter_usage; 00305 00306 struct impl; 00307 friend struct impl; 00308 impl* rep; 00309 }; 00310 00311 #include "rutz/debug.h" 00312 GVX_DBG_REGISTER 00313 00314 /* 00315 These macros make it slightly more convenient to make sure that 00316 *_Init() package initialization functions don't leak any exceptions 00317 (as they are called directly from C code within the Tcl core). 00318 */ 00319 00320 /// This macro should go at the top of each *_Init() function. 00321 /** Constructs a \c tcl::pkg with a Tcl interpreter, package name, and 00322 package version. The version string should be in the form MM.mm 00323 where MM is major version, and mm is minor version. This 00324 constructor can also correctly parse a version string such as 00325 given by the RCS revision tag. If you're using svn, the suggested 00326 form is to choose a fixed major version number, and let the svn 00327 revision be the minor number, so you would pass a version string 00328 such as "4.$Revision: 11876 $". */ 00329 #define GVX_PKG_CREATE(pkg, interp, pkgname, pkgversion) \ 00330 \ 00331 int GVX_PKG_STATUS = tcl::pkg::STATUS_ERR; \ 00332 { \ 00333 tcl::pkg* pkg = 0; \ 00334 \ 00335 try \ 00336 { pkg = tcl::pkg::create_in_macro(interp, pkgname, pkgversion); } \ 00337 catch (...) \ 00338 { return 1; } \ 00339 \ 00340 static bool recursive_initialization = false; \ 00341 GVX_ASSERT(!recursive_initialization); \ 00342 recursive_initialization = true; \ 00343 \ 00344 try \ 00345 { 00346 00347 00348 /// This macro should go at the end of each *_Init() function. 00349 #define GVX_PKG_RETURN(pkg) \ 00350 } \ 00351 catch(...) \ 00352 { \ 00353 pkg->handle_live_exception(SRC_POS); \ 00354 } \ 00355 recursive_initialization = false; \ 00356 GVX_PKG_STATUS = pkg->finish_init(); \ 00357 } \ 00358 return GVX_PKG_STATUS; 00359 00360 /// Use this instead of GVX_PKG_RETURN(pkg) if more work needs to be done after the package is initialized. 00361 #define GVX_PKG_FINISH(pkg) \ 00362 } \ 00363 catch(...) \ 00364 { \ 00365 pkg->handle_live_exception(SRC_POS); \ 00366 } \ 00367 recursive_initialization = false; \ 00368 GVX_PKG_STATUS = pkg->finish_init(); \ 00369 } 00370 00371 00372 static const char __attribute__((used)) vcid_groovx_tcl_pkg_h_utc20050628162421[] = "$Id: pkg.h 11876 2009-10-22 15:53:06Z icore $ $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/tcl/pkg.h $"; 00373 #endif // !GROOVX_TCL_PKG_H_UTC20050628162421_DEFINED