/** @file /common/TCL/tcl_script.cpp @author Petr Wolf */ #include #include "common/compatibility.h" #include "common/mm.h" #include "common/exc.h" #include "common/types.h" #include "common/TCL/tcl_script.h" #include "common/TCL/tcl_struct.h" #include "world/useful.h" #include "world/typedefs.h" using namespace std; TTCL_Interpreter::TTCL_Interpreter() { _interpreter = Tcl_CreateInterp(); } TTCL_Interpreter::~TTCL_Interpreter() { Tcl_DeleteInterp(_interpreter); //KMemFree(_interpreter); } void TTCL_Interpreter::init(TCL_SCRIPT * init_script) { TTCL_Script script(this); script.loadStruct(init_script); script.run(); } bool TTCL_Interpreter::setVar(const char * name, const TCL_VAR_TYPE type, void * value) { if (_interpreter == NULL) THROW(E_8K_TCL_Error, "TCL interpreter has not been initialized properly"); // odstraneni predchoziho vyskytu promenne Tcl_UnsetVar(_interpreter, name, 0); // nastaveni nove hodnoty bool result; char s[256]; switch (type) { case TVT_STRING: // STRING result = (Tcl_SetVar(_interpreter, name, (const char *)value, 0) != NULL); break; case TVT_INT: // INT // prevedu cislo na string snprintf(s, 255, "%d", *(int *)value); // ulozim cislo do TCL result = (Tcl_SetVar(_interpreter, name, s, 0) != NULL); break; case TVT_FLOAT: // FLOAT // prevedu cislo na string snprintf(s, 255, "%f", *(float *)value); // ulozim cislo do TCL result = (Tcl_SetVar(_interpreter, name, s, 0) != NULL); break; case TVT_FLOAT_LIST: { TTCL_Float_List * list = (TTCL_Float_List *)value; string hodnoty("set "); char s[MAX_STRLEN]; hodnoty += name; hodnoty += " [list"; for (TTCL_Float_List::iterator i = list->begin(); i != list->end(); i++) { snprintf(s, MAX_STRLEN, "%f", *i); hodnoty += " "; hodnoty += s; } hodnoty += "];"; result = (eval(hodnoty.data()) == TCL_OK) ? true : false; } break; case TVT_INT_LIST: { TTCL_Int_List * list = (TTCL_Int_List *)value; string hodnoty("set "); char s[MAX_STRLEN]; hodnoty += name; hodnoty += " [list"; for (TTCL_Int_List::iterator i = list->begin(); i != list->end(); i++) { snprintf(s, MAX_STRLEN, "%d", *i); hodnoty += " "; hodnoty += s; } hodnoty += "];"; result = (eval(hodnoty.data()) == TCL_OK) ? true : false; } break; case TVT_STRING_LIST: { TTCL_String_List * list = (TTCL_String_List *)value; string hodnoty("set "); hodnoty += name; hodnoty += " [list"; for (TTCL_String_List::iterator i = list->begin(); i != list->end(); i++) { hodnoty += " \""; hodnoty += addSlashes(*i); hodnoty += "\""; } hodnoty += "];"; result = (eval(hodnoty.data()) == TCL_OK) ? true : false; } break; case TVT_INT_ARRAY: case TVT_FLOAT_ARRAY: case TVT_STRING_ARRAY: // ARRAY - asociativni pole result = false; break; case TVT_HEX: { World::THex * str = (World::THex *)value; str->writeToTCL(*this, name); result = true; } break; case TVT_UNIT: { World::TLivingUnit * str = (World::TLivingUnit *)value; str->writeToTCL(*this, name); result = true; } break; case TVT_BUILDING: // TTCL_Struct objekty - umeji se samy zapsat do TCL { World::TLivingBuilding * str = (World::TLivingBuilding *)value; str->writeToTCL(*this, name); result = true; } break; default: result = false; } return result; } bool TTCL_Interpreter::getVar(const char * name, const TCL_VAR_TYPE type, void * value) { if (_interpreter == NULL) THROW(E_8K_TCL_Error, "TCL interpreter has not been initialized properly"); // nacteni objektu z TCL Tcl_Obj * tcl_obj = Tcl_GetVar2Ex(_interpreter, name, NULL, TCL_LEAVE_ERR_MSG); // promennou se nepodarilo nacist (a pritom to nebylo asociativni pole) if ((tcl_obj == NULL) && (type != TVT_INT_ARRAY) && (type != TVT_FLOAT_ARRAY) && (type != TVT_STRING_ARRAY)) { return false; } // nactu data a naplnim predanou promennou switch (type) { case TVT_STRING: if (strcpy((char *)value, Tcl_GetString(tcl_obj)) == NULL) return false; else return true; break; case TVT_INT: if (Tcl_GetIntFromObj(_interpreter, tcl_obj, (int *)value) == TCL_OK) return true; else return false; break; case TVT_FLOAT: double _value; if (Tcl_GetDoubleFromObj(_interpreter, tcl_obj, &_value) == TCL_OK) { // pretypovani na float *(float *)value = (float)_value; return true; } else return false; break; case TVT_INT_LIST: case TVT_FLOAT_LIST: case TVT_STRING_LIST: { int length; int i; char llength[MAX_STRLEN]; char lindex[MAX_STRLEN]; // zjistim delku seznamu snprintf(llength, MAX_STRLEN, "set %s [llength $%s]", TCL_SCRIPT_LENGTH_VARNAME, name); eval(llength); getVar(TCL_SCRIPT_LENGTH_VARNAME, TVT_INT, &length); // nactu prvky do vektoru - znovu rozlisim podle typu switch (type) { case TVT_INT_LIST: { int item_value; TTCL_Int_List * list = (TTCL_Int_List *)value; list->clear(); for (i = 0; i < length; i++) { snprintf(lindex, MAX_STRLEN, "set %s [lindex $%s %d]", TCL_SCRIPT_ITEM_VARNAME, name, i); eval(lindex); getVar(TCL_SCRIPT_ITEM_VARNAME, TVT_INT, &item_value); list->push_back(item_value); } } break; case TVT_FLOAT_LIST: { float item_value; TTCL_Float_List * list = (TTCL_Float_List *)value; list->clear(); for (i = 0; i < length; i++) { snprintf(lindex, MAX_STRLEN, "set %s [lindex $%s %d]", TCL_SCRIPT_ITEM_VARNAME, name, i); eval(lindex); getVar(TCL_SCRIPT_ITEM_VARNAME, TVT_FLOAT, &item_value); list->push_back(item_value); } } break; case TVT_STRING_LIST: { char item_value[MAX_STRLEN]; TTCL_String_List * list = (TTCL_String_List *)value; list->clear(); for (i = 0; i < length; i++) { snprintf(lindex, MAX_STRLEN, "set %s [lindex $%s %d]", TCL_SCRIPT_ITEM_VARNAME, name, i); eval(lindex); getVar(TCL_SCRIPT_ITEM_VARNAME, TVT_STRING, &item_value); list->push_back(item_value); } } break; } return true; } break; case TVT_INT_ARRAY: { //nactu jednotlive prvky predaneho asociativniho pole TTCL_Int_Array * array = (TTCL_Int_Array *)value; TTCL_Int_Array::iterator i; int item_value; char item_name[MAX_STRLEN]; for (i = array->begin(); i != array->end(); i++) { snprintf(item_name, MAX_STRLEN, "%s(%s)", name, i->first.data()); if (getVar(item_name, TVT_INT, &item_value)) { // hodnota nalezena i->second = item_value; } else { // hodnota nenalezena i->second = 0; } } return true; } break; case TVT_FLOAT_ARRAY: { //nactu jednotlive prvky predaneho asociativniho pole TTCL_Float_Array * array = (TTCL_Float_Array *)value; TTCL_Float_Array::iterator i; float item_value; char item_name[256]; for (i = array->begin(); i != array->end(); i++) { sprintf(item_name, "%s(%s)", name, i->first.data()); if (getVar(item_name, TVT_FLOAT, &item_value)) { // hodnota nalezena i->second = item_value; } else { // hodnota nebyla nalezena i->second = (float)0; } } return true; } break; case TVT_STRING_ARRAY: { //nactu jednotlive prvky predaneho asociativniho pole TTCL_String_Array * array = (TTCL_String_Array *)value; TTCL_String_Array::iterator i; char item_value[256]; char item_name[256]; for (i = array->begin(); i != array->end(); i++) { sprintf(item_name, "%s(%s)", name, i->first.data()); if (getVar(item_name, TVT_STRING, item_value)) { // hodnota nalezena i->second = item_value; } else { // hodnota nebyla nalezena i->second = ""; } } return true; } break; case TVT_HEX: case TVT_UNIT: case TVT_BUILDING: // TTCL_Struct objekty - umeji se samy nacist z TCL { TTCL_Struct * str = (TTCL_Struct *)value; str->readFromTCL(*this, name); return true; } default: return false; } } bool TTCL_Interpreter::getArray(const char * name, const TCL_VAR_TYPE type, const int count, void * values) { char item_name[MAX_STRLEN]; int i = 0; switch (type) { case TVT_INT: { int * array = (int *)values; for (i = 0; i < count; i++) { snprintf(item_name, MAX_STRLEN, "%s(%d)", name, i); if (!getVar(item_name, TVT_INT, &array[i])) { array[i] = 0; return false; } } } break; case TVT_FLOAT: { float * array = (float *)values; for (i = 0; i < count; i++) { snprintf(item_name, MAX_STRLEN, "%s(%d)", name, i); if (!getVar(item_name, TVT_FLOAT, &array[i])) { array[i] = 0; return false; } } } break; default: // not implemented return false; } return true; } bool TTCL_Interpreter::setArray(const char * name, const TCL_VAR_TYPE type, const int count, void * values) { char item_name[MAX_STRLEN]; char item_index[MAX_STRLEN]; int i = 0; switch (type) { case TVT_INT: { int * array = (int *)values; for (i = 0; i < count; i++) { snprintf(item_index, MAX_STRLEN, "%d", i); if (!setVar(TCL_path(item_name, name, item_index), TVT_INT, &array[i])) { return false; } } } break; case TVT_FLOAT: { float * array = (float *)values; for (i = 0; i < count; i++) { snprintf(item_index, MAX_STRLEN, "%d", i); if (!setVar(TCL_path(item_name, name, item_index), TVT_FLOAT, array + i)) { return false; } } } break; default: // not implemented return false; } return true; } bool TTCL_Interpreter::setConstInt(const char * name, const int value) { char s[MAX_STRLEN]; snprintf(s, MAX_STRLEN, "%d", value); return (Tcl_SetVar(_interpreter, name, s, 0) != NULL); } bool TTCL_Interpreter::setConstDouble(const char * name, const double value) { char s[MAX_STRLEN]; snprintf(s, MAX_STRLEN, "%.2f", value); return (Tcl_SetVar(_interpreter, name, s, 0) != NULL); } int TTCL_Interpreter::eval(const char * code) { if (_interpreter == NULL) THROW(E_8K_TCL_Error, "TCL interpreter has not been initialized properly"); int result = Tcl_Eval(_interpreter, code); if (result == TCL_ERROR) { THROW(E_8K_TCL_Error, Tcl_GetStringResult(_interpreter)); } return result; } const char * TTCL_Interpreter::getError() { return Tcl_GetStringResult(_interpreter); } Tcl_Command TTCL_Interpreter::createCommand(const char * tclName, Tcl_CmdProc * cName, ClientData clientData, Tcl_CmdDeleteProc * deleteProc) { return Tcl_CreateCommand(_interpreter, tclName, cName, clientData, deleteProc); } void TTCL_Interpreter::setResult(TCL_VAR_TYPE type, void * value) { char s[MAX_STRLEN]; switch (type) { case TVT_STRING: // STRING Tcl_SetResult(_interpreter, (char *)value, NULL); break; case TVT_INT: // INT // prevedu cislo na string snprintf(s, MAX_STRLEN, "%d", *(int *)value); Tcl_SetResult(_interpreter, s, NULL); break; case TVT_FLOAT: // FLOAT // prevedu cislo na string snprintf(s, MAX_STRLEN, "%f", *(float *)value); Tcl_SetResult(_interpreter, s, NULL); break; default: THROW(E_8K_TCL_UnknownType, ""); } } TTCL_Script::TTCL_Script() { _interpreter = NULL; } TTCL_Script::TTCL_Script(TTCL_Interpreter * interpreter) { _interpreter = interpreter; } TCL_VAR_TYPE TTCL_Script::_findType(const char * name, const bool input) { TCL_VAR * vars; int size; if (input) { // hledam mezi vstupnimi promennymi vars = _script->input; size = _script->input_size; } else { // hledam mezi vystupnimi promennymi vars = _script->output; size = _script->output_size; } for (int i = 0; i < size; i++) { if (strcmp(name, vars[i].name) == 0) return vars[i].type; } // promennou jsem nenasel, hodim vyjimku THROW(E_8K_TCL_UnknownVariable,""); } bool TTCL_Script::loadStruct(TCL_SCRIPT * script) { _script = script; return true; } int TTCL_Script::run() { int result; if (_interpreter == NULL) THROW(E_8K_TCL_Error, "TCL interpreter has not been initialized properly"); if (_script == NULL) THROW(E_8K_TCL_Error, "TCL script has not been initialized properly"); try { result = _interpreter->eval(_script->code); } catch (E_8K_TCL_Error &e) { throw e; } return result; } bool TTCL_Script::setVar(const char * name, void * value) { if (_interpreter == NULL) THROW(E_8K_TCL_Error, "TCL interpreter has not been initialized properly"); if (_script == NULL) THROW(E_8K_TCL_Error, "TCL script has not been initialized properly"); try { TCL_VAR_TYPE type = _findType(name, true); // vracim hodnotu nactenou z prostredi interpretu return _interpreter->setVar(name, type, value); } catch (E_8K_TCL_UnknownVariable) { // promenna daneho jmena nenalezena return false; } } bool TTCL_Script::getVar(const char * name, void * value) { if (_interpreter == NULL) THROW(E_8K_TCL_Error, "TCL interpreter has not been initialized properly"); if (_script == NULL) THROW(E_8K_TCL_Error, "TCL script has not been initialized properly"); try { TCL_VAR_TYPE type = _findType(name, false); // vracim hodnotu nactenou z prostredi interpretu if (_interpreter->getVar(name, type, value)) return true; else return false; } catch (E_8K_TCL_UnknownVariable) { // promenna daneho jmena nenalezena return false; } } bool TTCL_Script::joinIntLists(const char * ids, const char * values, std::map & target) { if (_interpreter == NULL) THROW(E_8K_TCL_Error, "TCL interpreter has not been initialized properly"); if (_script == NULL) THROW(E_8K_TCL_Error, "TCL script has not been initialized properly"); try { TTCL_Int_List ids_list; TCL_VAR_TYPE type = _findType(values, false); switch (type) { case TVT_INT_LIST: TTCL_Int_List values_list; _interpreter->getVar(ids, TVT_INT_LIST, &ids_list); _interpreter->getVar(values, type, &values_list); for (size_t i = 0; i < values_list.size(); i++) { target[ids_list[i]] = values_list[i]; } break; } return true; } catch (E_8K_TCL_Error) { return false; } }