26 static std::map<long, Setting*> traceMap;
27 static long traceCount = 0;
30 static int dummyClose(ClientData , Tcl_Interp* )
34 static int dummyInput(ClientData ,
char* ,
39 static void dummyWatch(ClientData ,
int )
42 static int dummyGetHandle(ClientData ,
int ,
47 Tcl_ChannelType Interpreter::channelType = {
48 const_cast<char*
>(
"openMSX console"),
52 Interpreter::outputProc,
69 Tcl_FindExecutable(programName);
73 : eventDistributor(eventDistributor_)
75 interp = Tcl_CreateInterp();
91 Tcl_Channel channel = Tcl_CreateChannel(&channelType,
92 "openMSX console",
this, TCL_WRITABLE);
94 Tcl_SetChannelOption(interp, channel,
"-translation",
"binary");
95 Tcl_SetChannelOption(interp, channel,
"-buffering",
"line");
96 Tcl_SetChannelOption(interp, channel,
"-encoding",
"utf-8");
98 Tcl_SetStdChannel(channel, TCL_STDOUT);
114 if (!Tcl_InterpDeleted(interp)) {
115 Tcl_DeleteInterp(interp);
127 int Interpreter::outputProc(ClientData clientData,
const char* buf,
131 auto* output =
static_cast<Interpreter*
>(clientData)->output;
133 if (!text.empty() && output) {
144 assert(commandTokenMap.
find(name) == commandTokenMap.
end());
145 commandTokenMap[name] = Tcl_CreateObjCommand(
146 interp, name.c_str(), commandProc,
147 static_cast<ClientData
>(&command),
nullptr);
152 auto it = commandTokenMap.
find(name);
153 assert(it != commandTokenMap.
end());
154 Tcl_DeleteCommandFromToken(interp, it->second);
155 commandTokenMap.
erase(it);
158 int Interpreter::commandProc(ClientData clientData, Tcl_Interp* interp,
159 int objc, Tcl_Obj*
const objv[])
162 auto& command = *
static_cast<Command*
>(clientData);
163 vector<TclObject> tokens;
164 tokens.reserve(objc);
165 for (
auto i :
xrange(objc)) {
166 tokens.push_back(
TclObject(interp, objv[i]));
171 if (!command.isAllowedInEmptyMachine()) {
172 if (
auto controller =
173 dynamic_cast<MSXCommandController*>(
174 &command.getCommandController())) {
175 if (!controller->getMSXMotherBoard().getMachineConfig()) {
176 throw CommandException(
177 "Can't execute command in empty machine");
181 command.execute(tokens, result);
182 }
catch (MSXException& e) {
184 "Interpreter: Got an exception while executing a command: "
186 result.setString(e.getMessage());
189 Tcl_SetObjResult(interp, result.getTclObject());
208 return Tcl_CommandComplete(command.c_str()) != 0;
213 int success = Tcl_Eval(interp, command.c_str());
214 string result = Tcl_GetStringResult(interp);
215 if (success != TCL_OK) {
223 int success = Tcl_EvalFile(interp, filename.c_str());
224 string result = Tcl_GetStringResult(interp);
225 if (success != TCL_OK) {
231 static void setVar(Tcl_Interp* interp,
const char* name,
const char* value)
233 if (!Tcl_SetVar(interp, name, value, TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)) {
235 std::cerr << Tcl_GetStringResult(interp) << std::endl;
238 static const char* getVar(Tcl_Interp* interp,
const char* name)
240 return Tcl_GetVar(interp, name, TCL_GLOBAL_ONLY);
245 if (!Tcl_SetVar(interp, name.c_str(), value.c_str(),
246 TCL_GLOBAL_ONLY | TCL_LEAVE_ERR_MSG)) {
253 Tcl_UnsetVar(interp, name.c_str(), TCL_GLOBAL_ONLY);
258 return getVar(interp, name.c_str());
261 static string getSafeValueString(
Setting& setting)
265 }
catch (MSXException&) {
313 long traceID = traceCount++;
314 traceMap[traceID] = &variable;
315 Tcl_TraceVar(interp, name.c_str(),
316 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
317 traceProc,
reinterpret_cast<ClientData
>(traceID));
322 auto it = traceMap.begin();
324 assert(it != traceMap.end());
325 if (it->second == &variable)
break;
329 long traceID = it->first;
330 Tcl_UntraceVar(interp, name.c_str(),
331 TCL_TRACE_READS | TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
332 traceProc,
reinterpret_cast<ClientData
>(traceID));
337 static Setting* getTraceSetting(
unsigned traceID)
339 auto it = traceMap.find(traceID);
340 return (it != traceMap.end()) ? it->second :
nullptr;
343 char* Interpreter::traceProc(ClientData clientData, Tcl_Interp* interp,
344 const char* part1,
const char* ,
int flags)
377 auto traceID =
reinterpret_cast<uintptr_t
>(clientData);
378 auto* variable = getTraceSetting(traceID);
379 if (!variable)
return nullptr;
381 static string static_string;
382 if (flags & TCL_TRACE_READS) {
384 setVar(interp, part1, variable->getValueString().c_str());
385 }
catch (MSXException& e) {
386 static_string = e.getMessage();
387 return const_cast<char*
>(static_string.c_str());
390 if (flags & TCL_TRACE_WRITES) {
392 const char* v = getVar(interp, part1);
393 string newValue = v ? v :
"";
394 variable->setValueStringDirect(newValue);
395 string newValue2 = variable->getValueString();
396 if (newValue != newValue2) {
397 setVar(interp, part1, newValue2.c_str());
399 }
catch (MSXException& e) {
400 setVar(interp, part1, getSafeValueString(*variable).c_str());
401 static_string = e.getMessage();
402 return const_cast<char*
>(static_string.c_str());
405 if (flags & TCL_TRACE_UNSETS) {
410 variable->setValueStringDirect(
411 variable->getRestoreValueString());
412 }
catch (MSXException&) {
418 setVar(interp, part1, getSafeValueString(*variable).c_str());
419 Tcl_TraceVar(interp, part1, TCL_TRACE_READS |
420 TCL_TRACE_WRITES | TCL_TRACE_UNSETS,
422 reinterpret_cast<ClientData>(traceID));
432 execute(
"namespace eval ::" + name +
" {}");
437 execute(
"namespace delete ::" + name);
449 if (Tcl_SplitList(interp, list.c_str(), &argc, &argv) == TCL_ERROR) {
451 interp ? Tcl_GetStringResult(interp)
452 :
"splitList error");
454 vector<string> result(argv, argv + argc);
455 Tcl_Free(reinterpret_cast<char*>(argv));
459 int Interpreter::signalEvent(
const std::shared_ptr<const Event>& event)
467 void Interpreter::poll()
470 Tcl_DoOneEvent(TCL_DONT_WAIT);