]> git.mxchange.org Git - flightgear.git/blob - src/Scripting/NasalSys.hxx
Merge branch 'next' of http://git.gitorious.org/fg/flightgear into next
[flightgear.git] / src / Scripting / NasalSys.hxx
1 #ifndef __NASALSYS_HXX
2 #define __NASALSYS_HXX
3
4 #include <simgear/misc/sg_path.hxx>
5 #include <simgear/structure/subsystem_mgr.hxx>
6 #include <simgear/misc/sg_dir.hxx>
7 #include <simgear/nasal/nasal.h>
8 #include <simgear/scene/model/modellib.hxx>
9 #include <simgear/xml/easyxml.hxx>
10
11 #include <map>
12 using std::map;
13
14
15 class FGNasalScript;
16 class FGNasalListener;
17
18 class FGNasalSys : public SGSubsystem
19 {
20 public:
21     FGNasalSys();
22     virtual ~FGNasalSys();
23     virtual void init();
24     virtual void update(double dt);
25
26     // Loads a nasal script from an external file and inserts it as a
27     // global module of the specified name.
28     bool loadModule(SGPath file, const char* moduleName);
29
30     // Simple hook to run arbitrary source code.  Returns a bool to
31     // indicate successful execution.  Does *not* return any Nasal
32     // values, because handling garbage-collected objects from C space
33     // is deep voodoo and violates the "simple hook" idea.
34     bool parseAndRun(const char* sourceCode);
35
36     // Slightly more complicated hook to get a handle to a precompiled
37     // Nasal script that can be invoked via a call() method.  The
38     // caller is expected to delete the FGNasalScript returned from
39     // this function.  The "name" argument specifies the "file name"
40     // for the source code that will be printed in Nasal stack traces
41     // on error.
42     FGNasalScript* parseScript(const char* src, const char* name=0);
43
44     // Implementation of the settimer extension function
45     void setTimer(naContext c, int argc, naRef* args);
46
47     // Implementation of the setlistener extension function
48     naRef setListener(naContext c, int argc, naRef* args);
49     naRef removeListener(naContext c, int argc, naRef* args);
50
51     // Returns a ghost wrapper for the current _cmdArg
52     naRef cmdArgGhost();
53
54     // Callbacks for command and timer bindings
55     virtual bool handleCommand(const SGPropertyNode* arg);
56
57     bool createModule(const char* moduleName, const char* fileName,
58                       const char* src, int len, const SGPropertyNode* cmdarg=0,
59                       int argc=0, naRef*args=0);
60
61     void deleteModule(const char* moduleName);
62
63     naRef call(naRef code, int argc, naRef* args, naRef locals);
64     naRef propNodeGhost(SGPropertyNode* handle);
65
66 private:
67     friend class FGNasalScript;
68     friend class FGNasalListener;
69     friend class FGNasalModuleListener;
70
71     //
72     // FGTimer subclass for handling Nasal timer callbacks.
73     // See the implementation of the settimer() extension function for
74     // more notes.
75     //
76     struct NasalTimer {
77         virtual void timerExpired();
78         virtual ~NasalTimer() {}
79         naRef handler;
80         int gcKey;
81         FGNasalSys* nasal;
82     };
83
84     // Listener
85     map<int, FGNasalListener *> _listener;
86     vector<FGNasalListener *> _dead_listener;
87     static int _listenerId;
88
89     void loadPropertyScripts();
90     void loadPropertyScripts(SGPropertyNode* n);
91     void loadScriptDirectory(simgear::Dir nasalDir);
92     void addModule(string moduleName, simgear::PathList scripts);
93     void hashset(naRef hash, const char* key, naRef val);
94     void logError(naContext);
95     naRef parse(const char* filename, const char* buf, int len);
96     naRef genPropsModule();
97
98     // This mechanism is here to allow naRefs to be passed to
99     // locations "outside" the interpreter.  Normally, such a
100     // reference would be garbage collected unexpectedly.  By passing
101     // it to gcSave and getting a key/handle, it can be cached in a
102     // globals.__gcsave hash.  Be sure to release it with gcRelease
103     // when done.
104     int gcSave(naRef r);
105     void gcRelease(int key);
106
107     naContext _context;
108     naRef _globals;
109
110     SGPropertyNode_ptr _cmdArg;
111
112     int _nextGCKey;
113     naRef _gcHash;
114     int _callCount;
115
116     public: void handleTimer(NasalTimer* t);
117 };
118
119
120 class FGNasalScript {
121 public:
122     ~FGNasalScript() { _nas->gcRelease(_gcKey); }
123
124     bool call() {
125         naRef n = naNil();
126         naCall(_nas->_context, _code, 0, &n, naNil(), naNil());
127         return naGetError(_nas->_context) == 0;
128     }
129
130 private:
131     friend class FGNasalSys;
132     naRef _code;
133     int _gcKey;
134     FGNasalSys* _nas;
135 };
136
137
138 class FGNasalListener : public SGPropertyChangeListener {
139 public:
140     FGNasalListener(SGPropertyNode* node, naRef code, FGNasalSys* nasal,
141                     int key, int id, int init, int type);
142
143     virtual ~FGNasalListener();
144     virtual void valueChanged(SGPropertyNode* node);
145     virtual void childAdded(SGPropertyNode* parent, SGPropertyNode* child);
146     virtual void childRemoved(SGPropertyNode* parent, SGPropertyNode* child);
147
148 private:
149     bool changed(SGPropertyNode* node);
150     void call(SGPropertyNode* which, naRef mode);
151
152     friend class FGNasalSys;
153     SGPropertyNode_ptr _node;
154     naRef _code;
155     int _gcKey;
156     int _id;
157     FGNasalSys* _nas;
158     int _init;
159     int _type;
160     unsigned int _active;
161     bool _dead;
162     long _last_int;
163     double _last_float;
164     string _last_string;
165 };
166
167
168 class FGNasalModelData : public simgear::SGModelData {
169 public:
170     FGNasalModelData(SGPropertyNode *root = 0) : _root(root), _unload(0) {}
171     ~FGNasalModelData();
172     void modelLoaded(const string& path, SGPropertyNode *prop, osg::Node *);
173
174 private:
175     static unsigned int _module_id;
176     string _module;
177     SGPropertyNode_ptr _root;
178     SGConstPropertyNode_ptr _unload;
179 };
180
181
182 class NasalXMLVisitor : public XMLVisitor {
183 public:
184     NasalXMLVisitor(naContext c, int argc, naRef* args);
185     virtual ~NasalXMLVisitor() { naFreeContext(_c); }
186
187     virtual void startElement(const char* tag, const XMLAttributes& a);
188     virtual void endElement(const char* tag);
189     virtual void data(const char* str, int len);
190     virtual void pi(const char* target, const char* data);
191
192 private:
193     void call(naRef func, int num, naRef a = naNil(), naRef b = naNil());
194     naRef make_string(const char* s, int n = -1);
195
196     naContext _c;
197     naRef _start_element, _end_element, _data, _pi;
198 };
199
200 #endif // __NASALSYS_HXX