pkg.h

Go to the documentation of this file.
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
Generated on Sun May 8 08:42:22 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3