/** * @brief Parser for setter command */ static bool UI_ParseSetAction (uiNode_t* node, uiAction_t* action, const char** text, const char** token, const char* errhead) { const value_t* property; int type; uiAction_t* localAction; assert((*token)[0] == '*'); Com_UnParseLastToken(); action->d.nonTerminal.left = UI_ParseExpression(text); type = action->d.nonTerminal.left->type; if (type != EA_VALUE_CVARNAME && type != EA_VALUE_CVARNAME_WITHINJECTION && type != EA_VALUE_PATHPROPERTY && type != EA_VALUE_PATHPROPERTY_WITHINJECTION) { Com_Printf("UI_ParseSetAction: Cvar or Node property expected. Type '%i' found\n", type); return false; } /* must use "equal" char between name and value */ *token = Com_EParse(text, errhead, nullptr); if (!*text) return false; if (!Q_streq(*token, "=")) { Com_Printf("UI_ParseSetAction: Assign sign '=' expected between variable and value. '%s' found in node %s.\n", *token, UI_GetPath(node)); return false; } /* get the value */ if (type == EA_VALUE_CVARNAME || type == EA_VALUE_CVARNAME_WITHINJECTION) { action->d.nonTerminal.right = UI_ParseExpression(text); return true; } property = (const value_t*) action->d.nonTerminal.left->d.terminal.d2.data; *token = Com_EParse(text, errhead, nullptr); if (!*text) return false; if (Q_streq(*token, "{")) { uiAction_t* actionList; if (property != nullptr && property->type != V_UI_ACTION) { Com_Printf("UI_ParseSetAction: Property %s@%s do not expect code block.\n", UI_GetPath(node), property->string); return false; } actionList = UI_ParseActionList(node, text, token); if (actionList == nullptr) return false; localAction = UI_AllocStaticAction(); localAction->type = EA_VALUE_RAW; localAction->d.terminal.d1.data = actionList; localAction->d.terminal.d2.integer = V_UI_ACTION; action->d.nonTerminal.right = localAction; return true; } if (Q_streq(*token, "(")) { Com_UnParseLastToken(); action->d.nonTerminal.right = UI_ParseExpression(text); return true; } /* @todo everything should come from UI_ParseExpression */ if (UI_IsInjectedString(*token)) { localAction = UI_AllocStaticAction(); localAction->type = EA_VALUE_STRING_WITHINJECTION; localAction->d.terminal.d1.data = UI_AllocStaticString(*token, 0); action->d.nonTerminal.right = localAction; return true; } localAction = UI_AllocStaticAction(); UI_InitRawActionValue(localAction, node, property, *token); action->d.nonTerminal.right = localAction; return true; }
/** * @brief Read a value from the stream and init an action with it * @return An initialized action else nullptr */ static uiAction_t *UI_ParseValueExpression (const char **text) { const char* token; uiAction_t *expression = UI_AllocStaticAction(); token = Com_Parse(text); if (*text == nullptr) { Com_Printf("UI_ParseTerminalExpression: Token expected\n"); return nullptr; } /* it is a const string (or an injection tag for compatibility) */ if (Com_GetType(text) == TT_QUOTED_WORD || token[0] == '<') { expression->d.terminal.d1.constString = UI_AllocStaticString(token, 0); if (UI_IsInjectedString(token)) expression->type = EA_VALUE_STRING_WITHINJECTION; else expression->type = EA_VALUE_STRING; return expression; } /* it is a param */ if (!Q_strncasecmp(token, "param", 5)) { if (!Q_strcasecmp(token, "paramcount")) { expression->type = EA_VALUE_PARAMCOUNT; return expression; } else if (token[5] >= '1' && token[5] <= '9') { int i; if (sscanf(token + 5, "%i", &i) == 1) { /* token range 1-9 already avoid 0 */ assert(i != 0); /** @todo when it is possible, we must check range of param id */ expression->type = EA_VALUE_PARAM; expression->d.terminal.d1.integer = i; return expression; } } } /* it is a cvarname */ if (char const* const cvarName = Q_strstart(token, "*cvar:")) { expression->d.terminal.d1.constString = UI_AllocStaticString(cvarName, 0); if (UI_IsInjectedString(cvarName)) expression->type = EA_VALUE_CVARNAME_WITHINJECTION; else expression->type = EA_VALUE_CVARNAME; return expression; } /* it is a node property or it is a OLD syntax node property */ /** @todo We MUST remove the OLD code as fast as possible */ if (char const* path = Q_strstart(token, "*")) { const char *propertyName; #if 0 /* it looks useless, an unused cache */ const value_t *property; #endif char const* const relativeToNode = Q_strstart(path, "node:"); if (relativeToNode) path = relativeToNode; if (UI_IsInjectedString(path)) expression->type = EA_VALUE_PATHPROPERTY_WITHINJECTION; else expression->type = EA_VALUE_PATHPROPERTY; if (!relativeToNode) { Com_Printf("UI_ParseExpression: Old syntax, please prefix '%s' with \"*node:root.\" \n", token); path = va("root.%s", path); } expression->d.terminal.d1.constString = UI_AllocStaticString(path, 0); /* get property name */ propertyName = strchr(path, '@'); if (propertyName == nullptr) { if (expression->type == EA_VALUE_PATHPROPERTY_WITHINJECTION) expression->type = EA_VALUE_PATHNODE_WITHINJECTION; else expression->type = EA_VALUE_PATHNODE; return expression; } propertyName++; return expression; } /* unsigned and signed number */ if ((token[0] >= '0' && token[0] <= '9') || (token[0] == '-' && token[1] >= '0' && token[1] <= '9')) { /** @todo use a better check - e.g. Com_ParseValue with V_INT or V_FLOAT */ float f = atof(token); expression->d.terminal.d1.number = f; expression->type = EA_VALUE_FLOAT; return expression; } /* boolean */ if (Q_streq(token, "true")) { expression->d.terminal.d1.number = 1.0; expression->type = EA_VALUE_FLOAT; return expression; } if (Q_streq(token, "false")) { expression->d.terminal.d1.number = 0.0; expression->type = EA_VALUE_FLOAT; return expression; } Com_Error(ERR_FATAL, "UI_ParseValueExpression: Token \"%s\" unknown. String must use quotes, cvar and nodes must use prefix.\n", token); }