]> git.mxchange.org Git - flightgear.git/blob - src/Scripting/nasal-props.cxx
Boris Koenig:
[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     naRef idx = naNumValue(naVec_get(args, 1));
156     SGPropertyNode* n;
157     if(naIsNil(idx) || !naIsNum(idx)) {
158         n = (*node)->getChild(naStr_data(child));
159     } else {
160         n = (*node)->getChild(naStr_data(child), (int)idx.num);
161     }
162     if(!n) return naNil();
163     return propNodeGhostCreate(c, n);
164 }
165
166 static naRef f_getChildren(naContext c, naRef args)
167 {
168     NODEARG();
169     naRef result = naNewVector(c);
170     if(naIsNil(args) || naVec_size(args) == 0) {
171         // Get all children
172         for(int i=0; i<(*node)->nChildren(); i++)
173             naVec_append(result, propNodeGhostCreate(c, (*node)->getChild(i)));
174     } else {
175         // Get all children of a specified name
176         naRef name = naVec_get(args, 0);
177         if(!naIsString(name)) return naNil();
178         vector<SGPropertyNode_ptr> children
179             = (*node)->getChildren(naStr_data(name));
180         for(unsigned int i=0; i<children.size(); i++)
181             naVec_append(result, propNodeGhostCreate(c, children[i]));
182     }
183     return result;
184 }
185
186 static naRef f_removeChild(naContext c, naRef args)
187 {
188     NODEARG();
189     naRef child = naVec_get(args, 0);
190     naRef index = naVec_get(args, 1);
191     if(!naIsString(child) || !naIsNum(index)) return naNil();
192     (*node)->removeChild(naStr_data(child), (int)index.num);
193     return naNil();
194 }
195
196 static naRef f_getNode(naContext c, naRef args)
197 {
198     NODEARG();
199     naRef path = naVec_get(args, 0);
200     bool create = naTrue(naVec_get(args, 1));
201     if(!naIsString(path)) return naNil();
202     SGPropertyNode* n = (*node)->getNode(naStr_data(path), create);
203     return propNodeGhostCreate(c, n);
204 }
205
206 static naRef f_new(naContext c, naRef args)
207 {
208     return propNodeGhostCreate(c, new SGPropertyNode());
209 }
210
211 static naRef f_globals(naContext c, naRef args)
212 {
213     return propNodeGhostCreate(c, globals->get_props());
214 }
215
216 struct {
217     naCFunction func;
218     char* name;
219 } propfuncs[] = {
220     { f_getType, "_getType" },
221     { f_getName, "_getName" },
222     { f_getIndex, "_getIndex" },
223     { f_getValue, "_getValue" },
224     { f_setValue, "_setValue" },
225     { f_setIntValue, "_setIntValue" },
226     { f_setBoolValue, "_setBoolValue" },
227     { f_setDoubleValue, "_setDoubleValue" },
228     { f_getParent, "_getParent" },
229     { f_getChild, "_getChild" },
230     { f_getChildren, "_getChildren" },
231     { f_removeChild, "_removeChild" },
232     { f_getNode, "_getNode" },
233     { f_new, "_new" },
234     { f_globals, "_globals" },
235     { 0, 0 }
236 };
237
238 naRef FGNasalSys::genPropsModule()
239 {
240     naRef namespc = naNewHash(_context);
241     for(int i=0; propfuncs[i].name; i++)
242         hashset(namespc, propfuncs[i].name,
243                 naNewFunc(_context, naNewCCode(_context, propfuncs[i].func)));
244     return namespc;
245 }