/** * @brief Read a path and return every we can use (node and property) * @details The path token must be a window name, and then node child. * Reserved token 'root' and 'parent' can be used to navigate. * If relativeNode is set, the path can start with reserved token * 'this', 'root' and 'parent' (relative to this node). * The function can return a node property by using a '\@', * the path 'foo\@pos' will return the window foo and the property 'pos' * from the 'window' behaviour. * @param[in] path Path to read. Contain a node location with dot seprator and a facultative property * @param[in] relativeNode relative node where the path start. It allow to use facultative command to start the path (this, parent, root). * @param[out] resultNode Node found. Else NULL. * @param[out] resultProperty Property found. Else NULL. * TODO Speed up, evilly used function, use strncmp instead of using buffer copy (name[MAX_VAR]) */ void UI_ReadNodePath (const char* path, const uiNode_t *relativeNode, uiNode_t **resultNode, const value_t **resultProperty) { char name[MAX_VAR]; uiNode_t* node = NULL; const char* nextName; char nextCommand = '^'; *resultNode = NULL; if (resultProperty) *resultProperty = NULL; nextName = path; while (nextName && nextName[0] != '\0') { const char* begin = nextName; char command = nextCommand; nextName = strpbrk(begin, ".@#"); if (!nextName) { Q_strncpyz(name, begin, sizeof(name)); nextCommand = '\0'; } else { assert(nextName - begin + 1 <= sizeof(name)); Q_strncpyz(name, begin, nextName - begin + 1); nextCommand = *nextName; nextName++; } switch (command) { case '^': /* first string */ if (Q_streq(name, "this")) { if (relativeNode == NULL) return; /** @todo find a way to fix the bad cast. only here to remove "discards qualifiers" warning */ node = *(uiNode_t**) ((void*)&relativeNode); } else if (Q_streq(name, "parent")) { if (relativeNode == NULL) return; node = relativeNode->parent; } else if (Q_streq(name, "root")) { if (relativeNode == NULL) return; node = relativeNode->root; } else node = UI_GetWindow(name); break; case '.': /* child node */ if (Q_streq(name, "parent")) node = node->parent; else if (Q_streq(name, "root")) node = node->root; else node = UI_GetNode(node, name); break; case '#': /* window index */ /** @todo FIXME use a warning instead of an assert */ assert(node->behaviour == ui_windowBehaviour); node = UI_WindowNodeGetIndexedChild(node, name); break; case '@': /* property */ assert(nextCommand == '\0'); *resultProperty = UI_GetPropertyFromBehaviour(node->behaviour, name); *resultNode = node; return; } if (!node) return; } *resultNode = node; return; }
/** * @brief Read a path and return every we can use (node and property) * @details The path token must be a window name, and then node child. * Reserved token 'root' and 'parent' can be used to navigate. * If relativeNode is set, the path can start with reserved token * 'this', 'root', 'parent' and 'child' (relative to this node). * The function can return a node property by using a '\@', * the path 'foo\@pos' will return the window foo and the property 'pos' * from the 'window' behaviour. * @param[in] path Path to read. Contain a node location with dot seprator and a facultative property * @param[in] relativeNode relative node where the path start. It allow to use facultative command to start the path (this, parent, root). * @param[in] iterationNode relative node referencing child in 'forchildin' iteration, mapped to '*node:child', can be nullptr * @param[out] resultNode Node found. Else nullptr. * @param[out] resultProperty Property found. Else nullptr. * @param[in,out] luaMethod A pointer to a value_t structure that is filled with a lua based method identification, can be nullptr * @note If luaMethod is set, the method will scan the known lua methods defined on the behaviour. If luaMethod is not set, only * registered local properties are scanned. * @todo Speed up, evilly used function, use strncmp instead of using buffer copy (name[MAX_VAR]) * @note If luaMethod is set, make sure to release the allocated .name string. */ void UI_ReadNodePath (const char* path, const uiNode_t* relativeNode, const uiNode_t* iterationNode, uiNode_t** resultNode, const value_t** resultProperty, value_t *luaMethod) { char name[MAX_VAR]; uiNode_t* node = nullptr; uiNode_t* childnode = nullptr; const char* nextName; char nextCommand = '^'; *resultNode = nullptr; if (resultProperty) *resultProperty = nullptr; nextName = path; while (nextName && nextName[0] != '\0') { const char* begin = nextName; char command = nextCommand; nextName = strpbrk(begin, ".@#"); if (!nextName) { Q_strncpyz(name, begin, sizeof(name)); nextCommand = '\0'; } else { assert(nextName - begin + 1 <= sizeof(name)); Q_strncpyz(name, begin, nextName - begin + 1); nextCommand = *nextName; nextName++; } switch (command) { case '^': /* first string */ if (Q_streq(name, "this")) { if (relativeNode == nullptr) return; node = const_cast<uiNode_t *>(relativeNode); } else if (Q_streq(name, "parent")) { if (relativeNode == nullptr) return; node = relativeNode->parent; } else if (Q_streq(name, "root")) { if (relativeNode == nullptr) return; node = relativeNode->root; } else if (Q_streq(name, "child")) { if (iterationNode == nullptr) return; node = const_cast<uiNode_t *>(iterationNode); } else node = UI_GetWindow(name); break; case '.': /* child node */ if (Q_streq(name, "parent")) childnode = node->parent; else if (Q_streq(name, "root")) childnode = node->root; else { childnode = UI_GetNode(node, name); /* if no node found and if we need it, then it is possible we call a lua based function */ if (luaMethod && !childnode) { *resultProperty = UI_GetPropertyOrLuaMethod(node, name, luaMethod); if (luaMethod->type) { childnode = node; } } } node = childnode; break; case '#': /* window index */ /** @todo FIXME use a warning instead of an assert */ assert(UI_Node_IsWindow(node)); node = UI_WindowNodeGetIndexedChild(node, name); break; case '@': /* property */ assert(nextCommand == '\0'); *resultProperty = UI_GetPropertyOrLuaMethod(node, name, luaMethod); *resultNode = node; return; } if (!node) return; } *resultNode = node; return; }