#endif
#include <string.h>
+#include <errno.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sstream>
#include <simgear/nasal/nasal.h>
+#include <simgear/nasal/iolib.h>
#include <simgear/props/props.hxx>
#include <simgear/math/sg_random.h>
#include <simgear/misc/sg_path.hxx>
#include <simgear/misc/sg_dir.hxx>
+#include <simgear/misc/SimpleMarkdown.hxx>
#include <simgear/structure/commands.hxx>
#include <simgear/math/sg_geodesy.hxx>
#include <simgear/structure/event_mgr.hxx>
void invoke()
{
+ if( _singleShot )
+ // Callback may restart the timer, so update status before callback is
+ // called (Prevent warnings of deleting not existing tasks from the
+ // event manager).
+ _isRunning = false;
+
naRef *args = NULL;
_sys->callMethod(_func, _self, 0, args, naNil() /* locals */);
- if (_singleShot) {
- _isRunning = false;
- }
}
void setSingleShot(bool aSingleShot)
naRef props = argc > 1 ? args[1] : naNil();
if(!naIsString(cmd) || (!naIsNil(props) && !naIsGhost(props)))
naRuntimeError(c, "bad arguments to fgcommand()");
- SGPropertyNode_ptr tmp, *node;
+ SGPropertyNode_ptr 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));
+ node = static_cast<SGPropertyNode*>(naGhost_ptr(props));
+ else
+ node = new SGPropertyNode;
+
+ return naNum(globals->get_commands()->execute(naStr_data(cmd), node));
}
// settimer(func, dt, simtime) extension function. Falls through to
}
TimerObj* timerObj = new TimerObj(nasalSys, func, self, args[0].num);
- return NasalTimerObj::create(c, timerObj);
+ return nasal::to_nasal(c, timerObj);
}
// setlistener(func, property, bool) extension function. Falls through to
}
// Sets up a property interpolation. The first argument is either a
-// ghost (SGPropertyNode_ptr*) or a string (global property path) to
+// ghost (SGPropertyNode*) or a string (global property path) to
// interpolate. The second argument is a vector of pairs of
// value/delta numbers.
static naRef f_interpolate(naContext c, naRef me, int argc, naRef* args)
SGPropertyNode* node;
naRef prop = argc > 0 ? args[0] : naNil();
if(naIsString(prop)) node = fgGetNode(naStr_data(prop), true);
- else if(naIsGhost(prop)) node = *(SGPropertyNode_ptr*)naGhost_ptr(prop);
+ else if(naIsGhost(prop)) node = static_cast<SGPropertyNode*>(naGhost_ptr(prop));
else return naNil();
naRef curve = argc > 1 ? args[1] : naNil();
return naNil();
}
+static naRef f_open(naContext c, naRef me, int argc, naRef* args)
+{
+ FILE* f;
+ naRef file = argc > 0 ? naStringValue(c, args[0]) : naNil();
+ naRef mode = argc > 1 ? naStringValue(c, args[1]) : naNil();
+ if(!naStr_data(file)) naRuntimeError(c, "bad argument to open()");
+ const char* modestr = naStr_data(mode) ? naStr_data(mode) : "rb";
+ std::string filename = fgValidatePath(naStr_data(file),
+ strcmp(modestr, "rb") && strcmp(modestr, "r"));
+ if(filename.empty()) {
+ SG_LOG(SG_NASAL, SG_ALERT, "open(): reading/writing '" <<
+ naStr_data(file) << "' denied (unauthorized directory - authorization"
+ " no longer follows symlinks; to authorize reading additional "
+ "directories, add them to --fg-aircraft)");
+ naRuntimeError(c, "open(): access denied (unauthorized directory)");
+ return naNil();
+ }
+ f = fopen(filename.c_str(), modestr);
+ if(!f) naRuntimeError(c, strerror(errno));
+ return naIOGhost(c, f);
+}
+
// Parse XML file.
// parsexml(<path> [, <start-tag> [, <end-tag> [, <data> [, <pi>]]]]);
//
if(!(naIsNil(args[i]) || naIsFunc(args[i])))
naRuntimeError(c, "parsexml(): callback argument not a function");
- const char* file = fgValidatePath(naStr_data(args[0]), false);
- if(!file) {
- naRuntimeError(c, "parsexml(): reading '%s' denied "
- "(unauthorized access)", naStr_data(args[0]));
+ std::string file = fgValidatePath(naStr_data(args[0]), false);
+ if(file.empty()) {
+ SG_LOG(SG_NASAL, SG_ALERT, "parsexml(): reading '" <<
+ naStr_data(args[0]) << "' denied (unauthorized directory - authorization"
+ " no longer follows symlinks; to authorize reading additional "
+ "directories, add them to --fg-aircraft)");
+ naRuntimeError(c, "parsexml(): access denied (unauthorized directory)");
return naNil();
}
- std::ifstream input(file);
+ std::ifstream input(file.c_str());
NasalXMLVisitor visitor(c, argc, args);
try {
readXML(input, visitor);
} catch (const sg_exception& e) {
naRuntimeError(c, "parsexml(): file '%s' %s",
- file, e.getFormattedMessage().c_str());
+ file.c_str(), e.getFormattedMessage().c_str());
return naNil();
}
- return naStr_fromdata(naNewString(c), const_cast<char*>(file), strlen(file));
+ return naStr_fromdata(naNewString(c), file.c_str(), file.length());
+}
+
+/**
+ * Parse very simple and small subset of markdown
+ *
+ * parse_markdown(src)
+ */
+static naRef f_parse_markdown(naContext c, naRef me, int argc, naRef* args)
+{
+ nasal::CallContext ctx(c, me, argc, args);
+ return ctx.to_nasal(
+ simgear::SimpleMarkdown::parse(ctx.requireArg<std::string>(0))
+ );
+}
+
+/**
+ * Create md5 hash from given string
+ *
+ * md5(str)
+ */
+static naRef f_md5(naContext c, naRef me, int argc, naRef* args)
+{
+ if( argc != 1 || !naIsString(args[0]) )
+ naRuntimeError(c, "md5(): wrong type or number of arguments");
+
+ return nasal::to_nasal(
+ c,
+ simgear::strutils::md5(naStr_data(args[0]), naStr_len(args[0]))
+ );
}
// Return UNIX epoch time in seconds.
{ "resolvepath", f_resolveDataPath },
{ "finddata", f_findDataDir },
{ "parsexml", f_parsexml },
+ { "parse_markdown", f_parse_markdown },
+ { "md5", f_md5 },
{ "systime", f_systime },
{ 0, 0 }
};
for(i=0; funcs[i].name; i++)
hashset(_globals, funcs[i].name,
naNewFunc(_context, naNewCCode(_context, funcs[i].func)));
-
+ nasal::Hash io_module = nasal::Hash(_globals, _context).get<nasal::Hash>("io");
+ io_module.set("open", f_open);
+
// And our SGPropertyNode wrapper
hashset(_globals, "props", genPropsModule());
.member("singleShot", &TimerObj::isSingleShot, &TimerObj::setSingleShot)
.member("isRunning", &TimerObj::isRunning);
+ // Set allowed paths for Nasal I/O
+ fgInitAllowedPaths();
+
// Now load the various source files in the Nasal directory
simgear::Dir nasalDir(SGPath(globals->get_fg_root(), "Nasal"));
loadScriptDirectory(nasalDir);
naRef args[1];
args[0] = propNodeGhost(aProps);
naContext ctx = naNewContext();
- naRef wrapped = naCall(ctx, _wrappedNodeFunc, 1, args, naNil(), naNil());
+ naRef wrapped = naCallMethodCtx(ctx, _wrappedNodeFunc, naNil(), 1, args, naNil());
naFreeContext(ctx);
return wrapped;
}
_unloadList.pop()->unload();
}
+ // Destroy all queued ghosts
+ nasal::ghostProcessDestroyList();
+
// The global context is a legacy thing. We use dynamically
// created contexts for naCall() now, so that we can call them
// recursively. But there are still spots that want to use it for
naGCRelease(key);
}
+
+//------------------------------------------------------------------------------
void FGNasalSys::NasalTimer::timerExpired()
{
nasal->handleTimer(this);
// setlistener(<property>, <func> [, <initial=0> [, <persistent=1>]])
// Attaches a callback function to a property (specified as a global
-// property path string or a SGPropertyNode_ptr* ghost). If the third,
+// property path string or a SGPropertyNode* ghost). If the third,
// optional argument (default=0) is set to 1, then the function is also
// called initially. If the fourth, optional argument is set to 0, then the
// function is only called when the property node value actually changes.
SGPropertyNode_ptr node;
naRef prop = argc > 0 ? args[0] : naNil();
if(naIsString(prop)) node = fgGetNode(naStr_data(prop), true);
- else if(naIsGhost(prop)) node = *(SGPropertyNode_ptr*)naGhost_ptr(prop);
+ else if(naIsGhost(prop)) node = static_cast<SGPropertyNode*>(naGhost_ptr(prop));
else {
naRuntimeError(c, "setlistener() with invalid property argument");
return naNil();