7#include <simgear/nasal/nasal.h>
8#include <simgear/props/props.hxx>
9#include <simgear/props/vectorPropTemplates.hxx>
30 SGPropertyNode* prop =
static_cast<SGPropertyNode*
>(ghost);
31 if (!SGPropertyNode::put(prop))
delete prop;
38 if(!ghost)
return naNil();
39 SGPropertyNode::get(ghost);
53 return static_cast<SGPropertyNode*
>(naGhost_ptr(ref));
56#define NASTR(s) s ? naStr_fromdata(naNewString(c),(char*)(s),strlen(s)) : naNil()
66 if(argc < 2 || !naIsGhost(args[0]) || \
67 naGhost_type(args[0]) != &PropNodeGhostType) \
68 naRuntimeError(c, "bad argument to props function"); \
69 SGPropertyNode_ptr node = static_cast<SGPropertyNode*>(naGhost_ptr(args[0]));
86#define MOVETARGET(cond1, create) \
88 naRef name = naVec_get(argv, 0); \
89 if(naIsString(name)) { \
91 node = node->getNode(naStr_data(name), create); \
92 } catch(const string& err) { \
93 naRuntimeError(c, (char *)err.c_str()); \
96 if(!node) return naNil(); \
97 naVec_removefirst(argv); \
106static naRef
f_getType(naContext c, naRef me,
int argc, naRef* args)
111 const char* t =
"unknown";
112 switch(node->getType()) {
113 case props::NONE: t =
"NONE";
break;
114 case props::ALIAS: t =
"ALIAS";
break;
115 case props::BOOL: t =
"BOOL";
break;
116 case props::INT: t =
"INT";
break;
117 case props::LONG: t =
"LONG";
break;
118 case props::FLOAT: t =
"FLOAT";
break;
119 case props::DOUBLE: t =
"DOUBLE";
break;
120 case props::STRING: t =
"STRING";
break;
121 case props::UNSPECIFIED: t =
"UNSPECIFIED";
break;
122 case props::VEC3D: t =
"VEC3D";
break;
123 case props::VEC4D: t =
"VEC4D";
break;
124 case props::EXTENDED: t =
"EXTENDED";
break;
133static naRef
f_isNumeric(naContext c, naRef me,
int argc, naRef* args)
138 switch(node->getType()) {
142 case props::DOUBLE:
return naNum(
true);
153static naRef
f_isInt(naContext c, naRef me,
int argc, naRef* args)
158 if ((node->getType() == props::INT) || (node->getType() == props::LONG)) {
173 if(naVec_size(argv) == 0)
return naNum(
unsigned(node->getAttributes()));
175 naRef val = naVec_get(argv, 0);
176 const char *a = naStr_data(val);
177 SGPropertyNode::Attribute attr;
179 if(!strcmp(a,
"last"))
return naNum(SGPropertyNode::LAST_USED_ATTRIBUTE);
180 else if(!strcmp(a,
"children"))
return naNum(node->nChildren());
181 else if(!strcmp(a,
"listeners"))
return naNum(node->nListeners());
183 else if(!strcmp(a,
"references"))
return naNum(node.getNumRefs() - 1);
184 else if(!strcmp(a,
"tied"))
return naNum(node->isTied());
185 else if(!strcmp(a,
"alias"))
return naNum(node->isAlias());
186 else if(!strcmp(a,
"readable")) attr = SGPropertyNode::READ;
187 else if(!strcmp(a,
"writable")) attr = SGPropertyNode::WRITE;
188 else if(!strcmp(a,
"archive")) attr = SGPropertyNode::ARCHIVE;
189 else if(!strcmp(a,
"trace-read")) attr = SGPropertyNode::TRACE_READ;
190 else if(!strcmp(a,
"trace-write")) attr = SGPropertyNode::TRACE_WRITE;
191 else if(!strcmp(a,
"userarchive")) attr = SGPropertyNode::USERARCHIVE;
192 else if(!strcmp(a,
"preserve")) attr = SGPropertyNode::PRESERVE;
193 else if(!strcmp(a,
"protected")) attr = SGPropertyNode::PROTECTED;
194 else if(!strcmp(a,
"listener-safe")) attr = SGPropertyNode::LISTENER_SAFE;
195 else if(!strcmp(a,
"value-changed-up")) attr = SGPropertyNode::VALUE_CHANGED_UP;
196 else if(!strcmp(a,
"value-changed-down")) attr = SGPropertyNode::VALUE_CHANGED_DOWN;
197 else if(!strcmp(a,
"translate")) attr = SGPropertyNode::TRANSLATE;
200 naRuntimeError(c,
"props.getAttribute() with invalid attribute: %s", a);
203 return naNum(node->getAttribute(attr));
218 if (node->getAttribute(SGPropertyNode::PROTECTED)) {
219 naRuntimeError(c,
"props.setAttribute() called on protected property %s",
220 node->getPath().c_str());
225 naRef val = naVec_get(argv, 0);
226 if(naVec_size(argv) == 1 && naIsNum(val)) {
227 naRef ret = naNum(node->getAttributes());
229 int attrs =
static_cast<int>(val.num) & (~SGPropertyNode::PROTECTED);
230 node->setAttributes(attrs);
233 SGPropertyNode::Attribute attr;
234 const char *a = naStr_data(val);
236 if(!strcmp(a,
"readable")) attr = SGPropertyNode::READ;
237 else if(!strcmp(a,
"writable")) attr = SGPropertyNode::WRITE;
238 else if(!strcmp(a,
"archive")) attr = SGPropertyNode::ARCHIVE;
239 else if(!strcmp(a,
"trace-read")) attr = SGPropertyNode::TRACE_READ;
240 else if(!strcmp(a,
"trace-write")) attr = SGPropertyNode::TRACE_WRITE;
241 else if(!strcmp(a,
"userarchive")) attr = SGPropertyNode::USERARCHIVE;
242 else if(!strcmp(a,
"preserve")) attr = SGPropertyNode::PRESERVE;
245 naRuntimeError(c,
"props.setAttribute() with invalid attribute");
248 naRef ret = naNum(node->getAttribute(attr));
249 node->setAttribute(attr, naTrue(naVec_get(argv, 1)) ?
true :
false);
257static naRef
f_getName(naContext c, naRef me,
int argc, naRef* args)
260 return NASTR(node->getNameString().c_str());
267static naRef
f_getIndex(naContext c, naRef me,
int argc, naRef* args)
270 return naNum(node->getIndex());
276static naRef
f_equals(naContext c, naRef me,
int argc, naRef* args)
280 naRef rhs = naVec_get(argv, 0);
284 SGPropertyNode* node_rhs =
static_cast<SGPropertyNode*
>(naGhost_ptr(rhs));
285 return naNum(node.ptr() == node_rhs);
291 const int num_components
292 =
sizeof(vec.data()) /
sizeof(
typename T::value_type);
293 naRef vector = naNewVector(c);
294 naVec_setsize(c, vector, num_components);
295 for (
int i = 0;
i < num_components; ++
i)
296 naVec_set(vector,
i, naNum(vec[
i]));
305static naRef
f_getValue(naContext c, naRef me,
int argc, naRef* args)
317 const int num_components
318 =
sizeof(vec.data()) /
sizeof(
typename T::value_type);
319 int size = naVec_size(vector);
321 for (
int i = 0;
i < num_components &&
i < size; ++
i) {
322 naRef element = naVec_get(vector,
i);
323 naRef n = naNumValue(element);
332 std::ostringstream message;
333 if (naIsNil(val)) message <<
"nil";
334 else if (naIsNum(val)) message <<
"num:" << naNumValue(val).num;
335 else if (naIsString(val)) message <<
"string:" << naStr_data(val);
336 else if (naIsScalar(val)) message <<
"scalar";
337 else if (naIsVector(val)) message <<
"vector";
338 else if (naIsHash(val)) message <<
"hash";
339 else if (naIsFunc(val)) message <<
"func";
340 else if (naIsCode(val)) message <<
"code";
341 else if (naIsCCode(val)) message <<
"ccode";
342 else if (naIsGhost(val)) message <<
"ghost";
344 return message.str();
352 if(naIsString(val)) {
353 result = node->setStringValue(naStr_data(val));
354 }
else if(naIsVector(val)) {
355 if(naVec_size(val) == 3)
357 else if(naVec_size(val) == 4)
360 naRuntimeError(c,
"props.setValue() vector value has wrong size");
361 }
else if(naIsNum(val)) {
362 double d = naNumValue(val).num;
363 if (SGMisc<double>::isNaN(d)) {
364 naRuntimeError(c,
"props.setValue() passed a NaN");
367 result = node->setDoubleValue(d);
368 }
else if (naIsNil(val)) {
372 naRuntimeError(c,
"props.setValue() called with unsupported value %s",
s_val_description(val).c_str());
374 return naNum(result);
385static naRef
f_setValue(naContext c, naRef me,
int argc, naRef* args)
389 naRef val = naVec_get(argv, 0);
401 naRef tmp0 = naVec_get(argv, 0);
402 naRef tmp1 = naNumValue(tmp0);
404 naRuntimeError(c,
"props.setIntValue() with non-number");
405 double tmp2 = tmp1.num;
408 return naNum(node->setIntValue(
iv));
415 naRef val = naVec_get(argv, 0);
416 return naNum(node->setBoolValue(naTrue(val) ?
true :
false));
425 if (node->getType() != props::BOOL) {
426 naRuntimeError(c,
"props.toggleBoolValue() on non-bool prop");
429 const auto val = node->getBoolValue();
430 return naNum(node->setBoolValue(val ?
false :
true));
437 naRef r = naNumValue(naVec_get(argv, 0));
439 naRuntimeError(c,
"props.setDoubleValue() with non-number");
441 if (SGMisc<double>::isNaN(r.num)) {
442 naRuntimeError(c,
"props.setDoubleValue() passed a NaN");
445 return naNum(node->setDoubleValue(r.num));
454 naRef r = naNumValue(naVec_get(argv, 0));
456 naRuntimeError(c,
"props.adjustValue() with non-number");
458 if (SGMisc<double>::isNaN(r.num)) {
459 naRuntimeError(c,
"props.adjustValue() passed a NaN");
462 switch(node->getType()) {
472 naRuntimeError(c,
"props.adjustValue() called on non-numeric type");
476 const auto dv = node->getDoubleValue();
477 return naNum(node->setDoubleValue(dv + r.num));
485 if (!naIsHash(hash)) {
486 naRuntimeError(c,
"props.setValues() with non-hash");
489 naRef keyvec = naNewVector(c);
490 naHash_keys(keyvec, hash);
493 for (
int i = 0;
i < naVec_size(keyvec);
i++) {
494 naRef key = naVec_get(keyvec,
i);
495 if (! naIsScalar(key)) {
496 naRuntimeError(c,
"props.setValues() with non-scalar key value");
498 char* keystr = naStr_data(naStringValue(c, key));
505static naRef
f_setValues(naContext c, naRef me,
int argc, naRef* args)
509 naRef val = naVec_get(argv, 0);
517 SGPropertyNode_ptr subnode = node->getNode(
name,
true);
519 if (naIsScalar(val)) {
521 }
else if (naIsHash(val)) {
523 }
else if (naIsVector(val)) {
525 for (
int i = 0;
i < naVec_size(val);
i++) {
526 const auto len = ::snprintf(nameBuf,
sizeof(nameBuf),
"%s[%i]",
name,
i);
527 if ((len < 0) || (len >= (
int)
sizeof(nameBuf))) {
528 naRuntimeError(c,
"Failed to create buffer for property name in setChildren");
532 }
else if (naIsNil(val)) {
543 }
catch(
const string& err) {
544 naRuntimeError(c, (
char *)err.c_str());
554 if(! naIsString(naVec_get(argv, 0))) {
555 naRuntimeError(c,
"props.setChildren() with non-string first argument");
558 char*
name = naStr_data(naVec_get(argv, 0));
559 naRef val = naVec_get(argv, 1);
566static naRef
f_getParent(naContext c, naRef me,
int argc, naRef* args)
569 SGPropertyNode* n = node->getParent();
570 if(!n)
return naNil();
582static naRef
f_getChild(naContext c, naRef me,
int argc, naRef* args)
585 naRef child = naVec_get(argv, 0);
586 if(!naIsString(child))
return naNil();
587 naRef idx = naNumValue(naVec_get(argv, 1));
588 bool create = naTrue(naVec_get(argv, 2)) != 0;
592 n = node->getChild(naStr_data(child), create);
594 n = node->getChild(naStr_data(child), (
int)idx.num, create);
596 }
catch (
const string& err) {
597 naRuntimeError(c, (
char *)err.c_str());
600 if(!n)
return naNil();
612 naRef result = naNewVector(c);
613 if(naIsNil(argv) || naVec_size(argv) == 0) {
615 for(
int i=0;
i<node->nChildren();
i++)
619 naRef
name = naVec_get(argv, 0);
620 if(!naIsString(
name))
return naNil();
622 vector<SGPropertyNode_ptr> children
623 = node->getChildren(naStr_data(
name));
624 for(
unsigned int i=0;
i<children.size();
i++)
626 }
catch (
const string& err) {
627 naRuntimeError(c, (
char *)err.c_str());
640static naRef
f_addChild(naContext c, naRef me,
int argc, naRef* args)
643 naRef child = naVec_get(argv, 0);
644 if(!naIsString(child))
return naNil();
645 naRef ref_min_index = naNumValue(naVec_get(argv, 1));
646 naRef ref_append = naVec_get(argv, 2);
651 if(!naIsNil(ref_min_index))
652 min_index = ref_min_index.num;
655 if(!naIsNil(ref_append))
656 append = naTrue(ref_append) != 0;
658 n = node->addChild(naStr_data(child), min_index, append);
660 catch (
const string& err)
662 naRuntimeError(c, (
char *)err.c_str());
672 naRef child = naVec_get(argv, 0);
673 if(!naIsString(child))
return naNil();
674 naRef ref_count = naNumValue(naVec_get(argv, 1));
675 naRef ref_min_index = naNumValue(naVec_get(argv, 2));
676 naRef ref_append = naVec_get(argv, 3);
680 if( !naIsNum(ref_count) )
681 throw string(
"props.addChildren() missing number of children");
682 count = ref_count.num;
685 if(!naIsNil(ref_min_index))
686 min_index = ref_min_index.num;
689 if(!naIsNil(ref_append))
690 append = naTrue(ref_append) != 0;
692 const simgear::PropertyList& nodes =
693 node->addChildren(naStr_data(child), count, min_index, append);
695 naRef result = naNewVector(c);
696 for(
size_t i = 0;
i < nodes.size(); ++
i )
700 catch (
const string& err)
702 naRuntimeError(c, (
char *)err.c_str());
716 naRef child = naVec_get(argv, 0);
717 naRef index = naVec_get(argv, 1);
718 if(!naIsString(child) || !naIsNum(index))
return naNil();
719 SGPropertyNode_ptr n;
721 n = node->getChild(naStr_data(child), (
int)index.num);
722 if (n && n->getAttribute(SGPropertyNode::PROTECTED)) {
723 naRuntimeError(c,
"props.Node.removeChild() called on protected child %s of %s",
724 naStr_data(child), node->getPath().c_str());
727 n = node->removeChild(naStr_data(child), (
int)index.num);
728 }
catch (
const string& err) {
729 naRuntimeError(c, (
char *)err.c_str());
743 naRef result = naNewVector(c);
744 if(naIsNil(argv) || naVec_size(argv) == 0) {
746 for(
int i = node->nChildren() - 1;
i >=0;
i--) {
747 SGPropertyNode_ptr n = node->getChild(
i);
748 if (n->getAttribute(SGPropertyNode::PROTECTED)) {
749 SG_LOG(SG_NASAL, SG_ALERT,
"props.Node.removeChildren: node " <<
750 n->getPath() <<
" is protected");
754 node->removeChild(
i);
759 naRef
name = naVec_get(argv, 0);
760 if(!naIsString(
name))
return naNil();
762 auto children = node->getChildren(naStr_data(
name));
763 for (
auto cn : children) {
764 if (cn->getAttribute(SGPropertyNode::PROTECTED)) {
765 SG_LOG(SG_NASAL, SG_ALERT,
"props.Node.removeChildren: node " <<
766 cn->getPath() <<
" is protected");
769 node->removeChild(cn);
772 }
catch (
const string& err) {
773 naRuntimeError(c, (
char *)err.c_str());
786 node->removeAllChildren();
796static naRef
f_alias(naContext c, naRef me,
int argc, naRef* args)
799 if (node->getAttribute(SGPropertyNode::PROTECTED)) {
800 naRuntimeError(c,
"props.Node.alias() called on protected property %s",
801 node->getPath().c_str());
805 naRef prop = naVec_get(argv, 0);
807 if(naIsString(prop)) al =
globals->get_props()->getNode(naStr_data(prop),
true);
808 else if(naIsGhost(prop)) al =
static_cast<SGPropertyNode*
>(naGhost_ptr(prop));
810 throw sg_exception(
"props.alias() with bad argument");
811 }
catch (sg_exception& err) {
812 naRuntimeError(c, err.what());
816 bool withListeners =
false;
817 if (naVec_size(argv) > 1) {
818 withListeners =
static_cast<int>(naVec_get(argv, 1).num) != 0;
820 return naNum(node->alias(al, withListeners));
828static naRef
f_unalias(naContext c, naRef me,
int argc, naRef* args)
831 return naNum(node->unalias());
835static naRef
f_location(naContext c, naRef me,
int argc, naRef* args)
838 const auto ls = node->getLocation().str();
839 return NASTR(ls.c_str());
858static naRef
f_getNode(naContext c, naRef me,
int argc, naRef* args)
861 naRef path = naVec_get(argv, 0);
862 bool create = naTrue(naVec_get(argv, 1)) != 0;
863 if(!naIsString(path))
return naNil();
866 n = node->getNode(naStr_data(path), create);
867 }
catch (
const string& err) {
868 naRuntimeError(c, (
char *)err.c_str());
878static naRef
f_new(naContext c, naRef me,
int argc, naRef* args)
889static naRef
f_globals(naContext c, naRef me,
int argc, naRef* args)
933naRef FGNasalSys::genPropsModule()
935 naRef namespc = naNewHash(d->_context);
938 naNewFunc(d->_context, naNewCCode(d->_context,
propfuncs[
i].func)));
948 switch(node->getType()) {
949 case props::BOOL:
case props::INT:
950 case props::LONG:
case props::FLOAT:
953 double dv = node->getDoubleValue();
954 if (SGMisc<double>::isNaN(dv)) {
955 SG_LOG(SG_NASAL, SG_ALERT,
"Nasal getValue: property " << node->getPath() <<
" is NaN");
963 case props::UNSPECIFIED:
964 return NASTR(node->getStringValue().c_str());
naRef propNodeGhostCreate(naContext c, SGPropertyNode *n)
static naRef getPropertyValue(naContext c, SGPropertyNode *node)
Convert the value of an SGPropertyNode to its Nasal representation.
void hashset(naRef hash, const char *key, naRef val)
Set member of specified hash to given value.
naRef propNodeGhost(SGPropertyNode *handle)
static naRef f_getNode(naContext c, naRef me, int argc, naRef *args)
static naRef f_getName(naContext c, naRef me, int argc, naRef *args)
static naRef f_unalias(naContext c, naRef me, int argc, naRef *args)
naRef makeVectorFromVec(naContext c, const T &vec)
static naRef f_setChildrenHelper(naContext c, SGPropertyNode_ptr node, char *name, naRef val)
static naRef f_removeAllChildren(naContext c, naRef me, int argc, naRef *args)
static naRef f_addChildren(naContext c, naRef me, int argc, naRef *args)
static void propNodeGhostDestroy(void *ghost)
static std::string s_val_description(naRef val)
static naRef f_getParent(naContext c, naRef me, int argc, naRef *args)
static naRef f_getIndex(naContext c, naRef me, int argc, naRef *args)
static naRef f_getAttribute(naContext c, naRef me, int argc, naRef *args)
static naRef f_toggleBoolValue(naContext c, naRef me, int argc, naRef *args)
static naRef f_location(naContext c, naRef me, int argc, naRef *args)
static naRef f_removeChild(naContext c, naRef me, int argc, naRef *args)
static naRef f_removeChildren(naContext c, naRef me, int argc, naRef *args)
static naRef f_equals(naContext c, naRef me, int argc, naRef *args)
static naRef f_globals(naContext c, naRef me, int argc, naRef *args)
static naRef f_setValueHelper(naContext c, SGPropertyNode_ptr node, naRef val)
static naRef f_getAliasTarget(naContext c, naRef me, int argc, naRef *args)
T makeVecFromVector(naRef vector)
static naRef f_setDoubleValue(naContext c, naRef me, int argc, naRef *args)
static naRef f_getChild(naContext c, naRef me, int argc, naRef *args)
SGPropertyNode * ghostToPropNode(naRef ref)
static naRef f_isInt(naContext c, naRef me, int argc, naRef *args)
static naRef f_getChildren(naContext c, naRef me, int argc, naRef *args)
static naRef f_new(naContext c, naRef me, int argc, naRef *args)
naRef propNodeGhostCreate(naContext c, SGPropertyNode *ghost)
static naRef f_alias(naContext c, naRef me, int argc, naRef *args)
static struct @240013025306215324344374206305351343354363373265 propfuncs[]
static naRef f_setBoolValue(naContext c, naRef me, int argc, naRef *args)
static naRef f_setValuesHelper(naContext c, SGPropertyNode_ptr node, naRef hash)
naGhostType PropNodeGhostType
static naRef f_addChild(naContext c, naRef me, int argc, naRef *args)
static naRef f_getValue(naContext c, naRef me, int argc, naRef *args)
static naRef f_setAttribute(naContext c, naRef me, int argc, naRef *args)
static naRef f_setValue(naContext c, naRef me, int argc, naRef *args)
static naRef f_setChildren(naContext c, naRef me, int argc, naRef *args)
static naRef f_getType(naContext c, naRef me, int argc, naRef *args)
#define MOVETARGET(cond1, create)
static naRef f_isNumeric(naContext c, naRef me, int argc, naRef *args)
static naRef f_adjustValue(naContext c, naRef me, int argc, naRef *args)
static naRef f_setValues(naContext c, naRef me, int argc, naRef *args)
static naRef f_setIntValue(naContext c, naRef me, int argc, naRef *args)