]> git.mxchange.org Git - flightgear.git/blob - src/Scripting/nasal-props.cxx
Fix for a premature deletion bug. The _arg SGPropertyNode* is passed
[flightgear.git] / src / Scripting / nasal-props.cxx
1 #include <simgear/nasal/nasal.h>
2 #include <simgear/props/props.hxx>
3
4 #include <Main/globals.hxx>
5
6 #include "NasalSys.hxx"
7
8 // Implementation of a Nasal wrapper for the SGPropertyNode class,
9 // using the Nasal "ghost" (er... Garbage collection Handle for
10 // OutSide Thingy) facility.
11 //
12 // Note that these functions appear in Nasal with prepended
13 // underscores.  They work on the low-level "ghost" objects and aren't
14 // intended for use from user code, but from Nasal code you will find
15 // in props.nas.  That is where the Nasal props.Node class is defined,
16 // which provides a saner interface along the lines of SGPropertyNode.
17
18 static void propNodeGhostDestroy(void* ghost)
19 {
20     SGPropertyNode_ptr* prop = (SGPropertyNode_ptr*)ghost;
21     delete prop;
22 }
23
24 naGhostType PropNodeGhostType = { propNodeGhostDestroy };
25
26 static naRef propNodeGhostCreate(naContext c, SGPropertyNode* n)
27 {
28     if(!n) return naNil();
29     SGPropertyNode_ptr* ghost = new SGPropertyNode_ptr(n);
30     return naNewGhost(c, &PropNodeGhostType, ghost);
31 }
32
33 naRef FGNasalSys::propNodeGhost(SGPropertyNode* handle)
34 {
35     return propNodeGhostCreate(_context, handle);
36 }
37
38 #define NASTR(s) s ? naStr_fromdata(naNewString(c),(char*)(s),strlen(s)) : naNil()
39
40 //
41 // Standard header for the extension functions.  It turns the "ghost"
42 // found in arg[0] into a SGPropertyNode_ptr*, and then "unwraps" the
43 // vector found in the second argument into a normal-looking args
44 // array.  This allows the Nasal handlers to do things like:
45 //   Node.getChild = func { _getChild(me.ghost, arg) }
46 //
47 #define NODEARG() \
48     naRef ghost = naVec_get(args, 0); \
49     SGPropertyNode_ptr* node = (SGPropertyNode_ptr*)naGhost_ptr(ghost); \
50     if(!node || naGhost_type(ghost) != &PropNodeGhostType) \
51         return naNil(); \
52     if(naVec_size(args) > 1) { \
53         args = naVec_get(args, 1); \
54         if(!naIsVector(args)) return naNil(); \
55     } else { args = naNil(); }
56
57 static naRef f_getType(naContext c, naRef args)
58 {
59     NODEARG();
60     char* t = "unknown";
61     switch((*node)->getType()) {
62     case SGPropertyNode::NONE:   t = "NONE";   break;
63     case SGPropertyNode::ALIAS:  t = "ALIAS";  break;
64     case SGPropertyNode::BOOL:   t = "BOOL";   break;
65     case SGPropertyNode::INT:    t = "INT";    break;
66     case SGPropertyNode::LONG:   t = "LONG";   break;
67     case SGPropertyNode::FLOAT:  t = "FLOAT";  break;
68     case SGPropertyNode::DOUBLE: t = "DOUBLE"; break;
69     case SGPropertyNode::STRING: t = "STRING"; break;
70     case SGPropertyNode::UNSPECIFIED: t = "UNSPECIFIED"; break;
71     }
72     return NASTR(t);
73 }
74
75 static naRef f_getName(naContext c, naRef args)
76 {
77     NODEARG();
78     return NASTR((*node)->getName());
79 }
80
81 static naRef f_getIndex(naContext c, naRef args)
82 {
83     NODEARG();
84     return naNum((*node)->getIndex());
85 }
86
87 static naRef f_getValue(naContext c, naRef args)
88 {
89     NODEARG();
90     switch((*node)->getType()) {
91     case SGPropertyNode::BOOL:   case SGPropertyNode::INT:
92     case SGPropertyNode::LONG:   case SGPropertyNode::FLOAT:
93     case SGPropertyNode::DOUBLE:
94         return naNum((*node)->getDoubleValue());
95     case SGPropertyNode::STRING:
96     case SGPropertyNode::UNSPECIFIED:
97         return NASTR((*node)->getStringValue());
98     }
99     return naNil();
100 }
101
102 static naRef f_setValue(naContext c, naRef args)
103 {
104     NODEARG();
105     naRef val = naVec_get(args, 0);
106     if(naIsString(val)) (*node)->setStringValue(naStr_data(val));
107     else                (*node)->setDoubleValue(naNumValue(val).num);
108     return naNil();
109 }
110
111 static naRef f_setIntValue(naContext c, naRef args)
112 {
113     NODEARG();
114     // Original code:
115     //   int iv = (int)naNumValue(naVec_get(args, 0)).num;
116
117     // Junk to pacify the gcc-2.95.3 optimizer:
118     naRef tmp0 = naVec_get(args, 0);
119     naRef tmp1 = naNumValue(tmp0);
120     double tmp2 = tmp1.num;
121     int iv = (int)tmp2;
122
123     (*node)->setIntValue(iv);
124     return naNil();
125 }
126
127 static naRef f_setBoolValue(naContext c, naRef args)
128 {
129     NODEARG();
130     naRef val = naVec_get(args, 0);
131     (*node)->setBoolValue(naTrue(val) ? true : false);
132     return naNil();
133 }
134
135 static naRef f_setDoubleValue(naContext c, naRef args)
136 {
137     NODEARG();
138     (*node)->setDoubleValue(naNumValue(naVec_get(args, 0)).num);
139     return naNil();
140 }
141
142 static naRef f_getParent(naContext c, naRef args)
143 {
144     NODEARG();
145     SGPropertyNode* n = (*node)->getParent();
146     if(!n) return naNil();
147     return propNodeGhostCreate(c, n);
148 }
149
150 static naRef f_getChild(naContext c, naRef args)
151 {
152     NODEARG();
153     naRef child = naVec_get(args, 0);
154     if(!naIsString(child)) return naNil();
155     SGPropertyNode* n = (*node)->getChild(naStr_data(child));
156     if(!n) return naNil();
157     return propNodeGhostCreate(c, n);
158 }
159
160 static naRef f_getChildren(naContext c, naRef args)
161 {
162     NODEARG();
163     naRef result = naNewVector(c);
164     if(naIsNil(args) || naVec_size(args) == 0) {
165         // Get all children
166         for(int i=0; i<(*node)->nChildren(); i++)
167             naVec_append(result, propNodeGhostCreate(c, (*node)->getChild(i)));
168     } else {
169         // Get all children of a specified name
170         naRef name = naVec_get(args, 0);
171         if(!naIsString(name)) return naNil();
172         vector<SGPropertyNode_ptr> children
173             = (*node)->getChildren(naStr_data(name));
174         for(int i=0; i<children.size(); i++)
175             naVec_append(result, propNodeGhostCreate(c, children[i]));
176     }
177     return result;
178 }
179
180 static naRef f_removeChild(naContext c, naRef args)
181 {
182     NODEARG();
183     naRef child = naVec_get(args, 0);
184     naRef index = naVec_get(args, 1);
185     if(!naIsString(child) || !naIsNum(index)) return naNil();
186     (*node)->removeChild(naStr_data(child), (int)index.num);
187     return naNil();
188 }
189
190 static naRef f_getNode(naContext c, naRef args)
191 {
192     NODEARG();
193     naRef path = naVec_get(args, 0);
194     bool create = naTrue(naVec_get(args, 1));
195     if(!naIsString(path)) return naNil();
196     SGPropertyNode* n = (*node)->getNode(naStr_data(path), create);
197     return propNodeGhostCreate(c, n);
198 }
199
200 static naRef f_new(naContext c, naRef args)
201 {
202     return propNodeGhostCreate(c, new SGPropertyNode());
203 }
204
205 static naRef f_globals(naContext c, naRef args)
206 {
207     return propNodeGhostCreate(c, globals->get_props());
208 }
209
210 struct {
211     naCFunction func;
212     char* name;
213 } propfuncs[] = {
214     { f_getType, "_getType" },
215     { f_getName, "_getName" },
216     { f_getIndex, "_getIndex" },
217     { f_getValue, "_getValue" },
218     { f_setValue, "_setValue" },
219     { f_setIntValue, "_setIntValue" },
220     { f_setBoolValue, "_setBoolValue" },
221     { f_setDoubleValue, "_setDoubleValue" },
222     { f_getParent, "_getParent" },
223     { f_getChild, "_getChild" },
224     { f_getChildren, "_getChildren" },
225     { f_removeChild, "_removeChild" },
226     { f_getNode, "_getNode" },
227     { f_new, "_new" },
228     { f_globals, "_globals" },
229     { 0, 0 }
230 };
231
232 naRef FGNasalSys::genPropsModule()
233 {
234     naRef namespc = naNewHash(_context);
235     for(int i=0; propfuncs[i].name; i++)
236         hashset(namespc, propfuncs[i].name,
237                 naNewFunc(_context, naNewCCode(_context, propfuncs[i].func)));
238     return namespc;
239 }