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_INTERP_CC_UTC20050628162421_DEFINED
00035 #define GROOVX_TCL_INTERP_CC_UTC20050628162421_DEFINED
00036
00037 #include "tcl/interp.h"
00038
00039 #include "rutz/demangle.h"
00040 #include "rutz/error.h"
00041 #include "rutz/fstring.h"
00042 #include "rutz/sfmt.h"
00043
00044 #include "tcl/list.h"
00045
00046 #include <exception>
00047 #include <tcl.h>
00048 #include <typeinfo>
00049
00050 #include "rutz/trace.h"
00051 #include "rutz/debug.h"
00052 GVX_DBG_REGISTER
00053
00054 using rutz::fstring;
00055
00056 namespace
00057 {
00058 void c_interp_delete_proc(void* clientdata, Tcl_Interp*) throw()
00059 {
00060 tcl::interpreter* intp = static_cast<tcl::interpreter*>(clientdata);
00061 intp->forget_interp();
00062 }
00063
00064 bool report_error(tcl::interpreter& interp, const tcl::obj& code,
00065 tcl::error_strategy strategy,
00066 const rutz::file_pos& where)
00067 {
00068 switch (strategy)
00069 {
00070 case tcl::THROW_ERROR:
00071 {
00072 const fstring msg =
00073 rutz::sfmt("error while evaluating %s:\n%s",
00074 Tcl_GetString(code.get()),
00075 interp.get_result<const char*>());
00076
00077
00078
00079 interp.reset_result();
00080
00081 throw rutz::error(msg, where);
00082 }
00083 break;
00084 case tcl::IGNORE_ERROR:
00085 return false;
00086 }
00087
00088 return false;
00089 }
00090 }
00091
00093
00094
00095
00097
00098 tcl::interpreter::interpreter(Tcl_Interp* interp) :
00099 m_interp(interp)
00100 {
00101 GVX_TRACE("tcl::interpreter::interpreter");
00102 if (interp == 0)
00103 throw rutz::error("tried to make tcl::interpreter "
00104 "with a null Tcl_Interp*", SRC_POS);
00105
00106 Tcl_CallWhenDeleted(m_interp, c_interp_delete_proc,
00107 static_cast<void*>(this));
00108 }
00109
00110 tcl::interpreter::interpreter(const tcl::interpreter& other) throw() :
00111 m_interp(other.m_interp)
00112 {
00113 GVX_TRACE("tcl::interpreter::interpreter(const interpreter&)");
00114
00115 if (m_interp != 0)
00116 {
00117 Tcl_CallWhenDeleted(m_interp, c_interp_delete_proc,
00118 static_cast<void*>(this));
00119 }
00120 }
00121
00122 tcl::interpreter::~interpreter() throw()
00123 {
00124 GVX_TRACE("tcl::interpreter::~interpreter");
00125
00126 if (m_interp != 0)
00127 Tcl_DontCallWhenDeleted(m_interp, c_interp_delete_proc,
00128 static_cast<void*>(this));
00129 }
00130
00132
00133
00134
00136
00137 Tcl_Interp* tcl::interpreter::intp() const
00138 {
00139 if (m_interp == 0)
00140 throw rutz::error("tcl::interpreter doesn't have a valid Tcl_Interp*",
00141 SRC_POS);
00142
00143 return m_interp;
00144 }
00145
00146 bool tcl::interpreter::is_deleted() const throw()
00147 {
00148 GVX_TRACE("tcl::interpreter::is_deleted");
00149
00150 return (m_interp == 0) || Tcl_InterpDeleted(m_interp);
00151 }
00152
00153 void tcl::interpreter::forget_interp() throw()
00154 {
00155 GVX_TRACE("tcl::interpreter::forget_interp");
00156 m_interp = 0;
00157 }
00158
00159 void tcl::interpreter::destroy() throw()
00160 {
00161 GVX_TRACE("tcl::interpreter::destroy");
00162
00163 if (m_interp != 0)
00164 {
00165 Tcl_DeleteInterp(m_interp);
00166 m_interp = 0;
00167 }
00168 }
00169
00171
00172
00173
00175
00176 void tcl::interpreter::pkg_provide(const char* name, const char* version)
00177 {
00178 GVX_TRACE("tcl::interpreter::pkg_provide");
00179 Tcl_PkgProvide(intp(), name, version);
00180 }
00181
00183
00184
00185
00187
00188 bool tcl::interpreter::eval_boolean_expr(const tcl::obj& obj) const
00189 {
00190 GVX_TRACE("tcl::interpreter::eval_boolean_expr");
00191
00192 int expr_result;
00193
00194 if (Tcl_ExprBooleanObj(intp(), obj.get(), &expr_result) != TCL_OK)
00195 {
00196 throw rutz::error("error evaluating boolean expression", SRC_POS);
00197 }
00198
00199 return bool(expr_result);
00200 }
00201
00203
00204
00205
00207
00208 bool tcl::interpreter::eval(const char* code,
00209 tcl::error_strategy strategy)
00210 {
00211 tcl::obj obj(tcl::convert_from(code));
00212 return eval(obj, strategy);
00213 }
00214
00215 bool tcl::interpreter::eval(const fstring& code,
00216 tcl::error_strategy strategy)
00217 {
00218 tcl::obj obj(tcl::convert_from(code));
00219 return eval(obj, strategy);
00220 }
00221
00222 bool tcl::interpreter::eval(const tcl::obj& code,
00223 tcl::error_strategy strategy)
00224 {
00225 GVX_TRACE("tcl::interpreter::eval");
00226
00227 if (!is_valid())
00228 throw rutz::error("Tcl_Interp* was null "
00229 "in tcl::interpreter::eval", SRC_POS);
00230
00231
00232
00233
00234
00235
00236
00237 if ( Tcl_EvalObjEx(intp(), code.get(),
00238 TCL_EVAL_DIRECT | TCL_EVAL_GLOBAL) == TCL_OK )
00239 return true;
00240
00241
00242
00243 return report_error(*this, code, strategy, SRC_POS);
00244 }
00245
00246 bool tcl::interpreter::eval_objv(const tcl::list& objv,
00247 tcl::error_strategy strategy)
00248 {
00249 GVX_TRACE("tcl::interpreter::eval_objv");
00250
00251 if (!this->is_valid())
00252 throw rutz::error("Tcl_Interp* was null "
00253 "in tcl::interpreter::eval", SRC_POS);
00254
00255 if ( Tcl_EvalObjv(this->intp(), objv.length(), objv.elements(),
00256 TCL_EVAL_GLOBAL) == TCL_OK )
00257 return true;
00258
00259
00260
00261 return report_error(*this, objv.as_obj(), strategy, SRC_POS);
00262 }
00263
00264 bool tcl::interpreter::eval_file(const char* fname)
00265 {
00266 GVX_TRACE("tcl::interpreter::eval_file");
00267 return (Tcl_EvalFile(intp(), fname) == TCL_OK);
00268 }
00269
00270 void tcl::interpreter::source_rc_file()
00271 {
00272 GVX_TRACE("tcl::interpreter::source_rc_file");
00273 Tcl_SourceRCFile(intp());
00274 }
00275
00277
00278
00279
00281
00282 void tcl::interpreter::reset_result() const
00283 {
00284 GVX_TRACE("tcl::interpreter::reset_result");
00285
00286 Tcl_ResetResult(intp());
00287 }
00288
00289 void tcl::interpreter::append_result(const char* msg) const
00290 {
00291 GVX_TRACE("tcl::interpreter::append_result(const char*)");
00292
00293 Tcl_AppendResult(intp(), msg, static_cast<char*>(0));
00294 }
00295
00296 void tcl::interpreter::append_result(const fstring& msg) const
00297 {
00298 GVX_TRACE("tcl::interpreter::append_result(const fstring&)");
00299
00300 Tcl_AppendResult(intp(), msg.c_str(), static_cast<char*>(0));
00301 }
00302
00303 Tcl_Obj* tcl::interpreter::get_obj_result() const
00304 {
00305 GVX_TRACE("tcl::interpreter::get_obj_result");
00306
00307 return Tcl_GetObjResult(intp());
00308 }
00309
00310 void tcl::interpreter::set_obj_result(Tcl_Obj* obj)
00311 {
00312 GVX_TRACE("tcl::interpreter::set_obj_result");
00313
00314 Tcl_SetObjResult(intp(), obj);
00315 }
00316
00318
00319
00320
00322
00323 void tcl::interpreter::set_global_var(const char* var_name,
00324 const tcl::obj& var) const
00325 {
00326 GVX_TRACE("tcl::interpreter::set_global_var");
00327
00328 if (Tcl_SetVar2Ex(intp(), const_cast<char*>(var_name), 0,
00329 var.get(), TCL_GLOBAL_ONLY) == 0)
00330 {
00331 throw rutz::error(rutz::sfmt("couldn't set global variable '%s'",
00332 var_name), SRC_POS);
00333 }
00334 }
00335
00336 void tcl::interpreter::unset_global_var(const char* var_name) const
00337 {
00338 GVX_TRACE("tcl::interpreter::unset_global_var");
00339
00340 if (Tcl_UnsetVar(intp(), const_cast<char*>(var_name),
00341 TCL_GLOBAL_ONLY) != TCL_OK)
00342 {
00343 throw rutz::error(rutz::sfmt("couldn't unset global variable '%s'",
00344 var_name), SRC_POS);
00345 }
00346 }
00347
00348 Tcl_Obj* tcl::interpreter::get_obj_global_var(const char* name1,
00349 const char* name2) const
00350 {
00351 GVX_TRACE("tcl::interpreter::get_obj_global_var");
00352 Tcl_Obj* obj = Tcl_GetVar2Ex(intp(),
00353 const_cast<char*>(name1),
00354 const_cast<char*>(name2),
00355 TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG);
00356
00357 if (obj == 0)
00358 {
00359 throw rutz::error(rutz::sfmt("couldn't get global variable '%s'",
00360 name1), SRC_POS);
00361 }
00362
00363 return obj;
00364 }
00365
00366 void tcl::interpreter::link_int(const char* var_name, int* addr,
00367 bool read_only)
00368 {
00369 GVX_TRACE("tcl::interpreter::link_int");
00370 dbg_eval_nl(3, var_name);
00371
00372 int flag = TCL_LINK_INT;
00373 if (read_only) flag |= TCL_LINK_READ_ONLY;
00374
00375 if ( Tcl_LinkVar(intp(), var_name,
00376 reinterpret_cast<char *>(addr), flag)
00377 != TCL_OK )
00378 throw rutz::error("error while linking int variable", SRC_POS);
00379 }
00380
00381 void tcl::interpreter::link_double(const char* var_name, double* addr,
00382 bool read_only)
00383 {
00384 GVX_TRACE("tcl::interpreter::link_double");
00385 dbg_eval_nl(3, var_name);
00386
00387 int flag = TCL_LINK_DOUBLE;
00388 if (read_only) flag |= TCL_LINK_READ_ONLY;
00389
00390 if ( Tcl_LinkVar(intp(), var_name,
00391 reinterpret_cast<char *>(addr), flag)
00392 != TCL_OK )
00393 throw rutz::error("error while linking double variable", SRC_POS);
00394 }
00395
00396 void tcl::interpreter::link_boolean(const char* var_name, int* addr,
00397 bool read_only)
00398 {
00399 GVX_TRACE("tcl::interpreter::link_boolean");
00400 dbg_eval_nl(3, var_name);
00401
00402 int flag = TCL_LINK_BOOLEAN;
00403 if (read_only) flag |= TCL_LINK_READ_ONLY;
00404
00405 if ( Tcl_LinkVar(intp(), var_name,
00406 reinterpret_cast<char *>(addr), flag)
00407 != TCL_OK )
00408 throw rutz::error("error while linking boolean variable", SRC_POS);
00409 }
00410
00411 void tcl::interpreter::handle_live_exception(const char* where,
00412 const rutz::file_pos& pos) throw()
00413 {
00414 GVX_TRACE("tcl::interpreter::handle_live_exception");
00415
00416 try
00417 {
00418 throw;
00419 }
00420 catch (std::exception& err)
00421 {
00422 dbg_print_nl(3, "caught (std::exception&)");
00423
00424 if (is_valid())
00425 {
00426 const char* what = err.what();
00427
00428 const fstring msg =
00429 rutz::sfmt("%s caught at %s:%d:\n%s%s",
00430 rutz::demangled_name(typeid(err)),
00431 pos.m_file_name, pos.m_line_no,
00432 ((where != 0 && where[0] != '\0')
00433 ? rutz::sfmt("%s: ", where).c_str()
00434 : ""),
00435 ((what != 0 && what[0] != '\0')
00436 ? rutz::sfmt("%s ", what).c_str()
00437 : ""));
00438
00439 append_result(msg);
00440 }
00441 }
00442 catch (...)
00443 {
00444 dbg_print_nl(3, "caught (...)");
00445
00446 if (is_valid())
00447 {
00448 const fstring msg =
00449 rutz::sfmt("exception of unknown type caught at %s:%d\n%s",
00450 pos.m_file_name, pos.m_line_no,
00451 ((where != 0 && where[0] != '\0')
00452 ? where
00453 : ""));
00454
00455 append_result(msg);
00456 }
00457 }
00458 }
00459
00460 void tcl::interpreter::background_error() throw()
00461 {
00462 GVX_TRACE("tcl::interpreter::background_error");
00463
00464 if (is_valid())
00465 Tcl_BackgroundError(m_interp);
00466 }
00467
00468 void tcl::interpreter::add_error_info(const char* info)
00469 {
00470 GVX_TRACE("tcl::interpreter::add_error_info");
00471
00472 Tcl_AddErrorInfo(intp(), info);
00473 }
00474
00475 void tcl::interpreter::clear_event_queue()
00476 {
00477 GVX_TRACE("tcl::interpreter::clear_event_queue");
00478 while (Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT) != 0)
00479 { }
00480 }
00481
00482 bool tcl::interpreter::has_command(const char* cmd_name) const
00483 {
00484 GVX_TRACE("tcl::interpreter::has_command");
00485 Tcl_CmdInfo info;
00486 int result = Tcl_GetCommandInfo(intp(), cmd_name, &info);
00487 return (result != 0);
00488 }
00489
00490 void tcl::interpreter::delete_command(const char* cmd_name)
00491 {
00492 GVX_TRACE("tcl::interpreter::delete_command");
00493
00494
00495
00496
00497
00498
00499
00500 if ( !is_deleted() )
00501 {
00502 Tcl_DeleteCommand(intp(), cmd_name);
00503 }
00504 }
00505
00506 fstring tcl::interpreter::get_proc_body(const char* proc_name)
00507 {
00508 GVX_TRACE("tcl::interpreter::get_proc_body");
00509 if (has_command(proc_name))
00510 {
00511 reset_result();
00512
00513 if (eval(rutz::sfmt("info body %s", proc_name)))
00514 {
00515 fstring result = get_result<const char*>();
00516 reset_result();
00517 return result;
00518 }
00519 }
00520
00521 return "";
00522 }
00523
00524 void tcl::interpreter::create_proc(const char* namesp, const char* proc_name,
00525 const char* args, const char* body)
00526 {
00527 GVX_TRACE("tcl::interpreter::create_proc");
00528
00529 if (namesp == 0 || (*namesp == '\0'))
00530 {
00531 namesp = "::";
00532 }
00533
00534 const fstring proc_cmd =
00535 rutz::sfmt("namespace eval %s { proc %s {%s} {%s} }",
00536 namesp, proc_name, args ? args : "", body);
00537
00538 eval(proc_cmd);
00539 }
00540
00541 void tcl::interpreter::delete_proc(const char* namesp, const char* proc_name)
00542 {
00543 GVX_TRACE("tcl::interpreter::delete_proc");
00544
00545
00546 const fstring cmd_str =
00547 rutz::sfmt("rename %s::%s \"\"",
00548 ((namesp != 0) && (*namesp != '\0')) ? namesp : "",
00549 proc_name);
00550
00551 eval(cmd_str);
00552 }
00553
00554 static const char __attribute__((used)) vcid_groovx_tcl_interp_cc_utc20050628162421[] = "$Id: interp.cc 10065 2007-04-12 05:54:56Z rjpeters $ $HeadURL: file:
00555 #endif // !GROOVX_TCL_INTERP_CC_UTC20050628162421_DEFINED