X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FScripting%2FNasalSys.cxx;h=991147e790c5619d3b4e0ad14e24f86fe1f47612;hb=50e19ee23970db9bf7314d74f0ed223d8bf702c0;hp=70eb70002cb380fd29cf0dc9b2d8f2656f48bc37;hpb=922812a9133ee3d302de16c5738b23596b11ab2d;p=flightgear.git diff --git a/src/Scripting/NasalSys.cxx b/src/Scripting/NasalSys.cxx index 70eb70002..991147e79 100644 --- a/src/Scripting/NasalSys.cxx +++ b/src/Scripting/NasalSys.cxx @@ -3,10 +3,15 @@ # include "config.h" #endif +#ifdef HAVE_SYS_TIME_H +# include // gettimeofday +#endif + #include #include #include #include +#include #include @@ -15,13 +20,19 @@ #include #include #include +#include #include +#include #include
#include
+#include #include "NasalSys.hxx" +static FGNasalSys* nasalSys = 0; + + // Read and return file contents in a single buffer. Note use of // stat() to get the file size. This is a win32 function, believe it // or not. :) Note the REALLY IMPORTANT use of the "b" flag to fopen. @@ -52,6 +63,7 @@ static char* readfile(const char* file, int* lenOut) FGNasalSys::FGNasalSys() { + nasalSys = this; _context = 0; _globals = naNil(); _gcHash = naNil(); @@ -82,6 +94,7 @@ naRef FGNasalSys::call(naRef code, naRef locals) FGNasalSys::~FGNasalSys() { + nasalSys = 0; map::iterator it, end = _listener.end(); for(it = _listener.begin(); it != end; ++it) delete it->second; @@ -108,7 +121,7 @@ FGNasalScript* FGNasalSys::parseScript(const char* src, const char* name) char buf[256]; if(!name) { - sprintf(buf, "FGNasalScript@%p", script); + sprintf(buf, "FGNasalScript@%p", (void *)script); name = buf; } @@ -243,10 +256,17 @@ static naRef f_print(naContext c, naRef me, int argc, naRef* args) // an argument. static naRef f_fgcommand(naContext c, naRef me, int argc, naRef* args) { - if(argc < 2 || !naIsString(args[0]) || !naIsGhost(args[1])) + naRef cmd = argc > 0 ? args[0] : naNil(); + naRef props = argc > 1 ? args[1] : naNil(); + if(!naIsString(cmd) || (!naIsNil(props) && !naIsGhost(props))) naRuntimeError(c, "bad arguments to fgcommand()"); - naRef cmd = args[0], props = args[1]; - SGPropertyNode_ptr* node = (SGPropertyNode_ptr*)naGhost_ptr(props); + SGPropertyNode_ptr tmp, *node; + if(!naIsNil(props)) + node = (SGPropertyNode_ptr*)naGhost_ptr(props); + else { + tmp = new SGPropertyNode(); + node = &tmp; + } return naNum(globals->get_commands()->execute(naStr_data(cmd), *node)); } @@ -254,8 +274,7 @@ static naRef f_fgcommand(naContext c, naRef me, int argc, naRef* args) // FGNasalSys::setTimer(). See there for docs. static naRef f_settimer(naContext c, naRef me, int argc, naRef* args) { - FGNasalSys* nasal = (FGNasalSys*)globals->get_subsystem("nasal"); - nasal->setTimer(argc, args); + nasalSys->setTimer(c, argc, args); return naNil(); } @@ -263,24 +282,21 @@ static naRef f_settimer(naContext c, naRef me, int argc, naRef* args) // FGNasalSys::setListener(). See there for docs. static naRef f_setlistener(naContext c, naRef me, int argc, naRef* args) { - FGNasalSys* nasal = (FGNasalSys*)globals->get_subsystem("nasal"); - return nasal->setListener(c, argc, args); + return nasalSys->setListener(c, argc, args); } // removelistener(int) extension function. Falls through to // FGNasalSys::removeListener(). See there for docs. static naRef f_removelistener(naContext c, naRef me, int argc, naRef* args) { - FGNasalSys* nasal = (FGNasalSys*)globals->get_subsystem("nasal"); - return nasal->removeListener(c, argc, args); + return nasalSys->removeListener(c, argc, args); } // Returns a ghost handle to the argument to the currently executing // command static naRef f_cmdarg(naContext c, naRef me, int argc, naRef* args) { - FGNasalSys* nasal = (FGNasalSys*)globals->get_subsystem("nasal"); - return nasal->cmdArgGhost(); + return nasalSys->cmdArgGhost(); } // Sets up a property interpolation. The first argument is either a @@ -305,7 +321,8 @@ static naRef f_interpolate(naContext c, naRef me, int argc, naRef* args) deltas[i] = naNumValue(naVec_get(curve, 2*i+1)).num; } - ((SGInterpolator*)globals->get_subsystem("interpolator")) + ((SGInterpolator*)globals->get_subsystem_mgr() + ->get_group(SGSubsystemMgr::INIT)->get_subsystem("interpolator")) ->interpolate(node, nPoints, values, deltas); return naNil(); @@ -342,6 +359,128 @@ static naRef f_directory(naContext c, naRef me, int argc, naRef* args) return result; } +// Parse XML file. +// parsexml( [, [, [, [, ]]]]); +// +// ... absolute path of an XML file +// ... callback function with two args: tag name, attribute hash +// ... callback function with one arg: tag name +// ... callback function with one arg: data +// ... callback function with two args: target, data +// (pi = "processing instruction") +// All four callback functions are optional and default to nil. +// The function returns nil on error, and the file name otherwise. +static naRef f_parsexml(naContext c, naRef me, int argc, naRef* args) +{ + if(argc < 1 || !naIsString(args[0])) + naRuntimeError(c, "parsexml(): path argument missing or not a string"); + if(argc > 5) argc = 5; + for(int i=1; iget_scenery()->get_elevation_m(lat, lon, 10000.0, elev, &mat)) + return naNil(); + naRef vec = naNewVector(c); + naVec_append(vec, naNum(elev)); + naRef matdata = naNil(); + if(mat) { + matdata = naNewHash(c); + naRef names = naNewVector(c); + const vector n = mat->get_names(); + for(unsigned int i=0; i(n[i].c_str()), n[i].size())); + HASHSET("names", 5, names); + HASHSET("solid", 5, naNum(mat->get_solid())); + HASHSET("friction_factor", 15, naNum(mat->get_friction_factor())); + HASHSET("rolling_friction", 16, naNum(mat->get_rolling_friction())); + HASHSET("load_resistance", 15, naNum(mat->get_load_resistance())); + HASHSET("bumpiness", 9, naNum(mat->get_bumpiness())); + HASHSET("light_coverage", 14, naNum(mat->get_light_coverage())); + } + naVec_append(vec, matdata); + return vec; +#undef HASHSET +} + // Table of extension functions. Terminate with zeros. static struct { char* name; naCFunction func; } funcs[] = { { "getprop", f_getprop }, @@ -356,6 +495,11 @@ static struct { char* name; naCFunction func; } funcs[] = { { "rand", f_rand }, { "srand", f_srand }, { "directory", f_directory }, + { "parsexml", f_parsexml }, + { "systime", f_systime }, + { "carttogeod", f_carttogeod }, + { "geodtocart", f_geodtocart }, + { "geodinfo", f_geodinfo }, { 0, 0 } }; @@ -476,7 +620,7 @@ void FGNasalSys::loadPropertyScripts() loadModule(p, module); } */ - + const char* src = n->getStringValue("script"); if(!n->hasChild("script")) src = 0; // Hrm... if(src) @@ -610,15 +754,20 @@ bool FGNasalSys::handleCommand(const SGPropertyNode* arg) // "saved" somehow lest they be inadvertently cleaned. In this case, // they are inserted into a globals.__gcsave hash and removed on // expiration. -void FGNasalSys::setTimer(int argc, naRef* args) +void FGNasalSys::setTimer(naContext c, int argc, naRef* args) { // Extract the handler, delta, and simtime arguments: naRef handler = argc > 0 ? args[0] : naNil(); - if(!(naIsCode(handler) || naIsCCode(handler) || naIsFunc(handler))) + if(!(naIsCode(handler) || naIsCCode(handler) || naIsFunc(handler))) { + naRuntimeError(c, "settimer() with invalid function argument"); return; + } naRef delta = argc > 1 ? args[1] : naNil(); - if(naIsNil(delta)) return; + if(naIsNil(delta)) { + naRuntimeError(c, "settimer() with invalid time argument"); + return; + } bool simtime = (argc > 2 && naTrue(args[2])) ? false : true; @@ -777,8 +926,7 @@ void FGNasalModelData::modelLoaded(const string& path, SGPropertyNode *prop, _module = path; const char *s = load ? load->getStringValue() : ""; - FGNasalSys *nas = (FGNasalSys *)globals->get_subsystem("nasal"); - nas->createModule(_module.c_str(), _module.c_str(), s, strlen(s), _props); + nasalSys->createModule(_module.c_str(), _module.c_str(), s, strlen(s), _props); } FGNasalModelData::~FGNasalModelData() @@ -786,8 +934,7 @@ FGNasalModelData::~FGNasalModelData() if(_module.empty()) return; - FGNasalSys *nas = (FGNasalSys *)globals->get_subsystem("nasal"); - if(!nas) { + if(!nasalSys) { SG_LOG(SG_NASAL, SG_ALERT, "Trying to run an script " "without Nasal subsystem present."); return; @@ -795,9 +942,65 @@ FGNasalModelData::~FGNasalModelData() if(_unload) { const char *s = _unload->getStringValue(); - nas->createModule(_module.c_str(), _module.c_str(), s, strlen(s), _props); + nasalSys->createModule(_module.c_str(), _module.c_str(), s, strlen(s), _props); + } + nasalSys->deleteModule(_module.c_str()); +} + + + +// NasalXMLVisitor class: handles EasyXML visitor callback for parsexml() +// +NasalXMLVisitor::NasalXMLVisitor(naContext c, int argc, naRef* args) : + _c(naSubContext(c)), + _start_element(argc > 1 ? args[1] : naNil()), + _end_element(argc > 2 ? args[2] : naNil()), + _data(argc > 3 ? args[3] : naNil()), + _pi(argc > 4 ? args[4] : naNil()) +{ +} + +void NasalXMLVisitor::startElement(const char* tag, const XMLAttributes& a) +{ + if(naIsNil(_start_element)) return; + naRef attr = naNewHash(_c); + for(int i=0; ideleteModule(_module.c_str()); + call(_start_element, 2, make_string(tag), attr); +} + +void NasalXMLVisitor::endElement(const char* tag) +{ + if(!naIsNil(_end_element)) call(_end_element, 1, make_string(tag)); +} + +void NasalXMLVisitor::data(const char* str, int len) +{ + if(!naIsNil(_data)) call(_data, 1, make_string(str, len)); +} + +void NasalXMLVisitor::pi(const char* target, const char* data) +{ + if (!naIsNil(_pi)) call(_pi, 2, make_string(target), make_string(data)); +} + +void NasalXMLVisitor::call(naRef func, int num, naRef a, naRef b) +{ + naRef args[2]; + args[0] = a; + args[1] = b; + naCall(_c, func, num, args, naNil(), naNil()); + if(naGetError(_c)) + naRethrowError(_c); +} + +naRef NasalXMLVisitor::make_string(const char* s, int n) +{ + return naStr_fromdata(naNewString(_c), const_cast(s), + n < 0 ? strlen(s) : n); }