00001
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00033
00034 #ifndef GROOVX_TCL_PKG_CC_UTC20050628162420_DEFINED
00035 #define GROOVX_TCL_PKG_CC_UTC20050628162420_DEFINED
00036
00037 #include "tcl/pkg.h"
00038
00039 #include "tcl/command.h"
00040 #include "tcl/interp.h"
00041 #include "tcl/list.h"
00042 #include "tcl/namesp.h"
00043
00044 #include "rutz/error.h"
00045 #include "rutz/fstring.h"
00046 #include "rutz/sfmt.h"
00047 #include "rutz/shared_ptr.h"
00048
00049 #include <tcl.h>
00050 #ifdef HAVE_TCLINT_H
00051 #include <tclInt.h>
00052 #endif
00053 #include <cctype>
00054 #include <iostream>
00055 #include <typeinfo>
00056 #include <string>
00057 #include <vector>
00058
00059 #include "rutz/trace.h"
00060 #include "rutz/debug.h"
00061 GVX_DBG_REGISTER
00062
00063 #if (TCL_MAJOR_VERSION > 8) || (TCL_MAJOR_VERSION == 8 && TCL_MINOR_VERSION >= 5)
00064 # define HAVE_TCL_NAMESPACE_API
00065 #else
00066 # undef HAVE_TCL_NAMESPACE_API
00067 #endif
00068
00069 using std::string;
00070 using std::vector;
00071 using rutz::shared_ptr;
00072
00073 namespace
00074 {
00075 bool VERBOSE_INIT = false;
00076
00077 int INIT_DEPTH = 0;
00078
00079
00080
00081
00082 string make_clean_pkg_name(const string& name)
00083 {
00084 string clean;
00085
00086 clean += char(toupper(name[0]));
00087
00088 for (size_t i = 1; i < name.length(); ++i)
00089 {
00090 if (name[i] != '-' && name[i] != '_')
00091 clean += char(tolower(name[i]));
00092 }
00093
00094 return clean;
00095 }
00096
00097 string make_clean_version_string(const string& s)
00098 {
00099 string::size_type dollar1 = s.find_first_of("$");
00100 string::size_type dollar2 = s.find_last_of("$");
00101
00102 if (dollar1 == dollar2)
00103 return s;
00104
00105 const string r = s.substr(dollar1,dollar2+1-dollar1);
00106
00107 string::size_type n1 = r.find_first_of("0123456789");
00108 string::size_type n2 = r.find_last_of("0123456789");
00109
00110 string result(s);
00111
00112 if (n1 != string::npos)
00113 {
00114 const string n = r.substr(n1,n2+1-n1);
00115 result.replace(dollar1, dollar2+1-dollar1, n);
00116 }
00117 else
00118 {
00119 result.replace(dollar1, dollar2+1-dollar1, "0");
00120 }
00121
00122 return result;
00123 }
00124
00125 void export_into(tcl::interpreter& interp,
00126 const char* from, const char* to,
00127 const char* pattern)
00128 {
00129 GVX_TRACE("export_into");
00130 const rutz::fstring cmd =
00131 rutz::sfmt("namespace eval %s { namespace import ::%s::%s }",
00132 to, from, pattern);
00133
00134 interp.eval(cmd);
00135 }
00136
00137 tcl::list get_command_list(tcl::interpreter& interp, const char* namesp)
00138 {
00139 tcl::obj saveresult = interp.get_result<tcl::obj>();
00140 rutz::fstring cmd = rutz::sfmt("info commands ::%s::*", namesp);
00141 interp.eval(cmd);
00142 tcl::list cmdlist = interp.get_result<tcl::list>();
00143 interp.set_result(saveresult);
00144 return cmdlist;
00145 }
00146
00147 const char* get_name_tail(const char* name)
00148 {
00149 const char* p = name;
00150 while (*p != '\0') ++p;
00151 while (--p > name) {
00152 if ((*p == ':') && (*(p-1) == ':')) {
00153 ++p;
00154 break;
00155 }
00156 }
00157 GVX_ASSERT(p >= name);
00158 return p;
00159 }
00160 }
00161
00162 const int tcl::pkg::STATUS_OK = TCL_OK;
00163 const int tcl::pkg::STATUS_ERR = TCL_ERROR;
00164
00166
00167
00168
00170
00171 struct tcl::pkg::impl
00172 {
00173 private:
00174 impl(const impl&);
00175 impl& operator=(const impl&);
00176
00177 public:
00178 impl(Tcl_Interp* interp, const char* name, const char* version);
00179
00180 ~impl() throw();
00181
00182 tcl::interpreter interp;
00183 string const namesp_name;
00184 string const pkg_name;
00185 string const version;
00186 int init_status;
00187 std::vector<shared_ptr<int> > owned_ints;
00188 std::vector<shared_ptr<double> > owned_doubles;
00189 exit_callback* on_exit;
00190
00191 static void c_exit_handler(void* clientdata)
00192 {
00193 GVX_TRACE("tcl::pkg-c_exit_handler");
00194 tcl::pkg* pkg = static_cast<tcl::pkg*>(clientdata);
00195 dbg_eval_nl(3, pkg->namesp_name());
00196 delete pkg;
00197 }
00198 };
00199
00200 tcl::pkg::impl::impl(Tcl_Interp* intp,
00201 const char* name, const char* vers) :
00202 interp(intp),
00203 namesp_name(name ? name : ""),
00204 pkg_name(make_clean_pkg_name(namesp_name)),
00205 version(make_clean_version_string(vers)),
00206 init_status(TCL_OK),
00207 owned_ints(),
00208 owned_doubles(),
00209 on_exit(0)
00210 {
00211 GVX_TRACE("tcl::pkg::impl::impl");
00212 }
00213
00214 tcl::pkg::impl::~impl() throw()
00215 {
00216 GVX_TRACE("tcl::pkg::impl::~impl");
00217 if (on_exit != 0)
00218 on_exit();
00219 }
00220
00221 tcl::pkg::pkg(Tcl_Interp* interp,
00222 const char* name, const char* version) :
00223 rep(0)
00224 {
00225 GVX_TRACE("tcl::pkg::pkg");
00226
00227 rep = new impl(interp, name, version);
00228
00229 ++INIT_DEPTH;
00230 }
00231
00232 tcl::pkg::~pkg() throw()
00233 {
00234 GVX_TRACE("tcl::pkg::~pkg");
00235
00236
00237 Tcl_DeleteExitHandler(&impl::c_exit_handler, static_cast<void*>(this));
00238
00239 try
00240 {
00241 #ifndef HAVE_TCL_NAMESPACE_API
00242 tcl::list cmdnames = get_command_list(rep->interp,
00243 rep->namesp_name.c_str());
00244
00245 for (unsigned int i = 0; i < cmdnames.length(); ++i)
00246 {
00247 Tcl_DeleteCommand(rep->interp.intp(),
00248 cmdnames.get<const char*>(i));
00249 }
00250 #else
00251 Tcl_Namespace* namesp =
00252 Tcl_FindNamespace(rep->interp.intp(), rep->namesp_name.c_str(),
00253 0, TCL_GLOBAL_ONLY);
00254 if (namesp != 0)
00255 Tcl_DeleteNamespace(namesp);
00256 #endif
00257 }
00258 catch (...)
00259 {
00260 rep->interp.handle_live_exception("tcl::pkg::~pkg", SRC_POS);
00261 }
00262
00263 delete rep;
00264 }
00265
00266 void tcl::pkg::on_exit(exit_callback* callback)
00267 {
00268 GVX_TRACE("tcl::pkg::on_exit");
00269 rep->on_exit = callback;
00270 }
00271
00272 int tcl::pkg::destroy_on_unload(Tcl_Interp* intp, const char* pkgname)
00273 {
00274 GVX_TRACE("tcl::pkg::destroy_on_unload");
00275 tcl::interpreter interp(intp);
00276 tcl::pkg* pkg = tcl::pkg::lookup(interp, pkgname);
00277 if (pkg != 0)
00278 {
00279 delete pkg;
00280 return 1;
00281 }
00282
00283 return 0;
00284 }
00285
00286 tcl::pkg* tcl::pkg::lookup(tcl::interpreter& interp, const char* name,
00287 const char* version) throw()
00288 {
00289 GVX_TRACE("tcl::pkg::lookup");
00290
00291 void* clientdata = 0;
00292
00293 const string clean_name = make_clean_pkg_name(name);
00294
00295 tcl::obj saveresult = interp.get_result<tcl::obj>();
00296
00297 const char* ver =
00298 Tcl_PkgRequireEx(interp.intp(), clean_name.c_str(),
00299 version, 0, &clientdata);
00300
00301 interp.set_result(saveresult);
00302
00303 if (ver != 0)
00304 {
00305 tcl::pkg* result = static_cast<tcl::pkg*>(clientdata);
00306
00307 result = dynamic_cast<tcl::pkg*>(result);
00308
00309 return result;
00310 }
00311
00312 return 0;
00313 }
00314
00315 int tcl::pkg::init_status() const throw()
00316 {
00317 GVX_TRACE("tcl::pkg::init_status");
00318 if (rep->interp.get_result<const char*>()[0] != '\0')
00319 {
00320 rep->init_status = TCL_ERROR;
00321 }
00322 return rep->init_status;
00323 }
00324
00325 tcl::interpreter& tcl::pkg::interp() throw()
00326 {
00327 GVX_TRACE("tcl::pkg::interp");
00328 return rep->interp;
00329 }
00330
00331 void tcl::pkg::handle_live_exception(const rutz::file_pos& pos) throw()
00332 {
00333 GVX_TRACE("tcl::pkg::handle_live_exception");
00334 rep->interp.handle_live_exception(rep->pkg_name.c_str(), pos);
00335 this->set_init_status_error();
00336 }
00337
00338 void tcl::pkg::namesp_alias(const char* namesp, const char* pattern)
00339 {
00340 GVX_TRACE("tcl::pkg::namesp_alias");
00341
00342 export_into(rep->interp, rep->namesp_name.c_str(), namesp, pattern);
00343 }
00344
00345 void tcl::pkg::inherit_namesp(const char* namesp, const char* pattern)
00346 {
00347 GVX_TRACE("tcl::pkg::inherit_namesp");
00348
00349
00350 export_into(rep->interp, namesp, rep->namesp_name.c_str(), pattern);
00351
00352
00353
00354 const tcl::namesp otherns = tcl::namesp::lookup(rep->interp, namesp);
00355
00356 const tcl::list exportlist = otherns.get_export_list(rep->interp);
00357
00358 const tcl::namesp thisns(rep->interp, rep->namesp_name.c_str());
00359
00360 for (unsigned int i = 0; i < exportlist.size(); ++i)
00361 {
00362 thisns.export_cmd(rep->interp, exportlist.get<const char*>(i));
00363 }
00364 }
00365
00366 void tcl::pkg::inherit_pkg(const char* name, const char* version)
00367 {
00368 GVX_TRACE("tcl::pkg::inherit_pkg");
00369
00370 tcl::pkg* other = lookup(rep->interp, name, version);
00371
00372 if (other == 0)
00373 throw rutz::error(rutz::sfmt("no tcl::pkg named '%s'", name),
00374 SRC_POS);
00375
00376 inherit_namesp(other->namesp_name());
00377 }
00378
00379 const char* tcl::pkg::namesp_name() throw()
00380 {
00381 return rep->namesp_name.c_str();
00382 }
00383
00384 const char* tcl::pkg::pkg_name() const throw()
00385 {
00386 return rep->pkg_name.c_str();
00387 }
00388
00389 const char* tcl::pkg::version() const throw()
00390 {
00391 return rep->version.c_str();
00392 }
00393
00394 const char* tcl::pkg::make_pkg_cmd_name(const char* cmd_name_cstr,
00395 int flags)
00396 {
00397 GVX_TRACE("tcl::pkg::make_pkg_cmd_name");
00398 string cmd_name(cmd_name_cstr);
00399
00400
00401
00402
00403
00404 if (cmd_name.find("::") != string::npos)
00405 {
00406 return cmd_name_cstr;
00407 }
00408 else
00409 {
00410 if (!(flags & NO_EXPORT))
00411 {
00412 const tcl::namesp ns(rep->interp, rep->namesp_name.c_str());
00413
00414 ns.export_cmd(rep->interp, cmd_name_cstr);
00415 }
00416
00417 static string name;
00418 name = namesp_name();
00419 name += "::";
00420 name += cmd_name;
00421 return name.c_str();
00422 }
00423 }
00424
00425 void tcl::pkg::eval(const char* script)
00426 {
00427 GVX_TRACE("tcl::pkg::eval");
00428 rep->interp.eval(script);
00429 }
00430
00431 void tcl::pkg::link_var(const char* var_name, int& var)
00432 {
00433 GVX_TRACE("tcl::pkg::link_var int");
00434 rep->interp.link_int(var_name, &var, false);
00435 }
00436
00437 void tcl::pkg::link_var(const char* var_name, double& var)
00438 {
00439 GVX_TRACE("tcl::pkg::link_var double");
00440 rep->interp.link_double(var_name, &var, false);
00441 }
00442
00443 void tcl::pkg::link_var_copy(const char* var_name, int var)
00444 {
00445 GVX_TRACE("tcl::pkg::link_var_copy int");
00446 shared_ptr<int> copy(new int(var));
00447 rep->owned_ints.push_back(copy);
00448 rep->interp.link_int(var_name, copy.get(), true);
00449 }
00450
00451 void tcl::pkg::link_var_copy(const char* var_name, double var)
00452 {
00453 GVX_TRACE("tcl::pkg::link_var_copy double");
00454 shared_ptr<double> copy(new double(var));
00455 rep->owned_doubles.push_back(copy);
00456 rep->interp.link_double(var_name, copy.get(), true);
00457 }
00458
00459 void tcl::pkg::link_var_const(const char* var_name, int& var)
00460 {
00461 GVX_TRACE("tcl::pkg::link_var_const int");
00462 rep->interp.link_int(var_name, &var, true);
00463 }
00464
00465 void tcl::pkg::link_var_const(const char* var_name, double& var)
00466 {
00467 GVX_TRACE("tcl::pkg::link_var_const double");
00468 rep->interp.link_double(var_name, &var, true);
00469 }
00470
00471 void tcl::pkg::set_init_status_error() throw()
00472 {
00473 GVX_TRACE("tcl::pkg::set_init_status_error");
00474 rep->init_status = TCL_ERROR;
00475 }
00476
00477 void tcl::pkg::verbose_init(bool verbose) throw()
00478 {
00479 GVX_TRACE("tcl::pkg::verbose_init");
00480
00481 VERBOSE_INIT = verbose;
00482 }
00483
00484 int tcl::pkg::finish_init() throw()
00485 {
00486 GVX_TRACE("tcl::pkg::finish_init");
00487
00488 --INIT_DEPTH;
00489
00490 if (rep->init_status == TCL_OK)
00491 {
00492 if (VERBOSE_INIT)
00493 {
00494 for (int i = 0; i < INIT_DEPTH; ++i)
00495 std::cerr << " ";
00496 std::cerr << pkg_name() << " initialized.\n";
00497 }
00498
00499 if ( !rep->pkg_name.empty() && !rep->version.empty() )
00500 {
00501 Tcl_PkgProvideEx(rep->interp.intp(),
00502 rep->pkg_name.c_str(), rep->version.c_str(),
00503 static_cast<void*>(this));
00504 }
00505
00506 Tcl_CreateExitHandler(&impl::c_exit_handler,
00507 static_cast<void*>(this));
00508
00509 return rep->init_status;
00510 }
00511
00512
00513
00514 delete this;
00515 return TCL_ERROR;
00516 }
00517
00518 const char* const tcl::pkg::action_usage = "objref(s)";
00519 const char* const tcl::pkg::getter_usage = "objref(s)";
00520 const char* const tcl::pkg::setter_usage = "objref(s) new_value(s)";
00521
00522 static const char __attribute__((used)) vcid_groovx_tcl_pkg_cc_utc20050628162420[] = "$Id: pkg.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00523 #endif // !GROOVX_TCL_PKG_CC_UTC20050628162420_DEFINED