/** * Parse a string according to a property type, and allocate a raw value to the static memory * * @param action Action to initialize * @param node Current node we are parsing, only used for error message * @param property Type of the value to parse, if nullptr the string is not stored as string * @param string String value to parse * @return True if the action is initialized * @todo remove node param and catch error where we call that function */ bool UI_InitRawActionValue (uiAction_t* action, uiNode_t* node, const value_t* property, const char* string) { if (property == nullptr) { action->type = EA_VALUE_STRING; action->d.terminal.d1.data = UI_AllocStaticString(string, 0); action->d.terminal.d2.integer = 0; return true; } if (property->type == V_UI_SPRITEREF) { uiSprite_t* sprite = UI_GetSpriteByName(string); if (sprite == nullptr) { Com_Printf("UI_ParseSetAction: sprite '%s' not found (%s)\n", string, UI_GetPath(node)); return false; } action->type = EA_VALUE_RAW; action->d.terminal.d1.data = sprite; action->d.terminal.d2.integer = property->type; return true; } else { const int baseType = property->type & V_UI_MASK; if (baseType != 0 && baseType != V_UI_CVAR) { Com_Printf("UI_ParseRawValue: setter for property '%s' (type %d, 0x%X) is not supported (%s)\n", property->string, property->type, property->type, UI_GetPath(node)); return false; } ui_global.curadata = (byte*) Com_AlignPtr(ui_global.curadata, (valueTypes_t) (property->type & V_BASETYPEMASK)); action->type = EA_VALUE_RAW; action->d.terminal.d1.data = ui_global.curadata; action->d.terminal.d2.integer = property->type; /** @todo we should hide use of ui_global.curadata */ ui_global.curadata += Com_EParseValue(ui_global.curadata, string, (valueTypes_t) (property->type & V_BASETYPEMASK), 0, property->size); return true; } }
/** * @brief Parse a property value * @todo don't read the next token (need to change the script language) */ static bool UI_ParseProperty (void* object, const value_t* property, const char* objectName, const char** text, const char** token) { const char* errhead = "UI_ParseProperty: unexpected end of file (object"; static const char* notWellFormedValue = "UI_ParseProperty: \"%s\" is not a well formed node name (it must be quoted, uppercase const, a number, or prefixed with '*')\n"; size_t bytes; int result; const int specialType = property->type & V_UI_MASK; if (property->type == V_NULL) { return false; } switch (specialType) { case V_NOT_UI: /* common type */ *token = Com_EParse(text, errhead, objectName); if (!*text) return false; if (!UI_TokenIsValue(*token, Com_GetType(text) == TT_QUOTED_WORD)) { Com_Printf(notWellFormedValue, *token); return false; } if (property->type == V_TRANSLATION_STRING) { /* selectbox values are static arrays */ char* const target = Com_GetValue<char[]>(object, property); const char* translatableToken = *token; assert(property->size); if (translatableToken[0] == '_') translatableToken++; Q_strncpyz(target, translatableToken, property->size); } else { result = Com_ParseValue(object, *token, property->type, property->ofs, property->size, &bytes); if (result != RESULT_OK) { Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError()); return false; } } break; case V_UI_REF: *token = Com_EParse(text, errhead, objectName); if (!*text) return false; if (!UI_TokenIsValue(*token, Com_GetType(text) == TT_QUOTED_WORD)) { Com_Printf(notWellFormedValue, *token); return false; } /* a reference to data is handled like this */ ui_global.curadata = (byte*) Com_AlignPtr(ui_global.curadata, (valueTypes_t) (property->type & V_BASETYPEMASK)); Com_GetValue<byte*>(object, property) = ui_global.curadata; /** @todo check for the moment its not a cvar */ assert((*token)[0] != '*'); /* sanity check */ if ((property->type & V_BASETYPEMASK) == V_STRING && strlen(*token) > MAX_VAR - 1) { Com_Printf("UI_ParseProperty: Value '%s' is too long (key %s)\n", *token, property->string); return false; } result = Com_ParseValue(ui_global.curadata, *token, (valueTypes_t) (property->type & V_BASETYPEMASK), 0, property->size, &bytes); if (result != RESULT_OK) { Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError()); return false; } ui_global.curadata += bytes; break; case V_UI_CVAR: /* common type */ *token = Com_EParse(text, errhead, objectName); if (!*text) return false; if (!UI_TokenIsValue(*token, Com_GetType(text) == TT_QUOTED_WORD)) { Com_Printf(notWellFormedValue, *token); return false; } /* references are parsed as string */ if ((*token)[0] == '*') { /* a reference to data */ ui_global.curadata = (byte*) Com_AlignPtr(ui_global.curadata, V_STRING); Com_GetValue<byte*>(object, property) = ui_global.curadata; /* sanity check */ if (strlen(*token) > MAX_VAR - 1) { Com_Printf("UI_ParseProperty: Value '%s' is too long (key %s)\n", *token, property->string); return false; } result = Com_ParseValue(ui_global.curadata, *token, V_STRING, 0, 0, &bytes); if (result != RESULT_OK) { Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError()); return false; } ui_global.curadata += bytes; } else { /* a reference to data */ ui_global.curadata = (byte*) Com_AlignPtr(ui_global.curadata, (valueTypes_t)(property->type & V_BASETYPEMASK)); Com_GetValue<byte*>(object, property) = ui_global.curadata; /* sanity check */ if ((property->type & V_BASETYPEMASK) == V_STRING && strlen(*token) > MAX_VAR - 1) { Com_Printf("UI_ParseProperty: Value '%s' is too long (key %s)\n", *token, property->string); return false; } result = Com_ParseValue(ui_global.curadata, *token, (valueTypes_t)(property->type & V_BASETYPEMASK), 0, property->size, &bytes); if (result != RESULT_OK) { Com_Printf("UI_ParseProperty: Invalid value for property '%s': %s\n", property->string, Com_GetLastParseError()); return false; } ui_global.curadata += bytes; } break; case V_UI: switch ((int)property->type) { case V_UI_ACTION: result = UI_ParseEventProperty(static_cast<uiNode_t*>(object), property, text, token, errhead); if (!result) return false; break; case V_UI_EXCLUDERECT: result = UI_ParseExcludeRect(static_cast<uiNode_t*>(object), text, token, errhead); if (!result) return false; break; case V_UI_SPRITEREF: { *token = Com_EParse(text, errhead, objectName); if (!*text) return false; uiSprite_t const*& sprite = Com_GetValue<uiSprite_t const*>(object, property); sprite = UI_GetSpriteByName(*token); if (!sprite) { Com_Printf("UI_ParseProperty: sprite '%s' not found (object %s)\n", *token, objectName); } } break; case V_UI_IF: { *token = Com_EParse(text, errhead, objectName); if (!*text) return false; uiAction_t*& expression = Com_GetValue<uiAction_t*>(object, property); expression = UI_AllocStaticStringCondition(*token); if (!expression) return false; } break; case V_UI_DATAID: { *token = Com_EParse(text, errhead, objectName); if (!*text) return false; int& dataId = Com_GetValue<int>(object, property); dataId = UI_GetDataIDByName(*token); if (dataId < 0) { Com_Printf("UI_ParseProperty: Could not find shared data ID '%s' (%s@%s)\n", *token, objectName, property->string); return false; } } break; default: Com_Printf("UI_ParseProperty: unknown property type '%d' (0x%X) (%s@%s)\n", property->type, property->type, objectName, property->string); return false; } break; default: Com_Printf("UI_ParseProperties: unknown property type '%d' (0x%X) (%s@%s)\n", property->type, property->type, objectName, property->string); return false; } return true; }
static void CL_ParsePtlCmds (const char *name, const char **text) { ptlCmd_t *pc; const value_t *pp; const char *errhead = "CL_ParsePtlCmds: unexpected end of file"; const char *token; int i, j; /* get it's body */ token = Com_Parse(text); if (!*text || *token != '{') { Com_Printf("CL_ParsePtlCmds: particle cmds \"%s\" without body ignored\n", name); return; } do { token = Com_EParse(text, errhead, name); if (!*text) break; if (*token == '}') break; for (i = 0; i < PC_NUM_PTLCMDS; i++) if (Q_streq(token, pc_strings[i])) { /* allocate an new cmd */ if (numPtlCmds >= MAX_PTLCMDS) Com_Error(ERR_DROP, "CL_ParsePtlCmds: MAX_PTLCMDS exceeded"); pc = &ptlCmd[numPtlCmds++]; OBJZERO(*pc); pc->cmd = i; if (!pc_types[i]) break; /* get parameter type */ token = Com_EParse(text, errhead, name); if (!*text) return; /* operate on the top element on the stack */ if (token[0] == '#') { pc->ref = RSTACK; if (token[1] == '.') pc->ref -= (token[2] - '0'); break; } if (token[0] == '*') { int len; char baseComponentToken[MAX_VAR]; /* it's a variable reference */ token++; /* we maybe have to modify it */ Q_strncpyz(baseComponentToken, token, sizeof(baseComponentToken)); /* check for component specifier */ len = strlen(baseComponentToken); /* it's possible to change only the second value of e.g. a vector * just defined e.g. 'size.2' to modify the second value of size */ if (len >= 2 && baseComponentToken[len - 2] == '.') { baseComponentToken[len - 2] = 0; } else len = 0; for (pp = pps; pp->string; pp++) if (Q_streq(baseComponentToken, pp->string)) break; if (!pp->string) { Com_Printf("CL_ParsePtlCmds: bad reference \"%s\" specified (particle %s)\n", token, name); numPtlCmds--; break; } if ((pc_types[i] & PTL_ONLY_ONE_TYPE)) { if ((pc_types[i] & ~PTL_ONLY_ONE_TYPE) != pp->type) { Com_Printf("CL_ParsePtlCmds: bad type in var \"%s\" (PTL_ONLY_ONE_TYPE) specified (particle %s) (ptl type: %i (pc_type: %i), string: %s)\n", token, name, pp->type, pc_types[i], pc_strings[i]); numPtlCmds--; break; } } else if (pp->type >= V_NUM_TYPES || !((1 << pp->type) & pc_types[i])) { Com_Printf("CL_ParsePtlCmds: bad type in var \"%s\" specified (particle %s) (ptl type: %i (pc_type: %i), string: %s)\n", token, name, pp->type, pc_types[i], pc_strings[i]); numPtlCmds--; break; } if (len) { /* get single component */ if ((1 << pp->type) & V_VECS) { const int component = (baseComponentToken[len - 1] - '1'); /* get the component we want to modify */ if (component > 3) { Com_Printf("CL_ParsePtlCmds: bad component value - it's bigger than 3: %i (particle %s)\n", component, name); numPtlCmds--; break; } pc->type = V_FLOAT; /* go to component offset */ pc->ref = -((int)pp->ofs) - component * sizeof(float); break; } else { Com_Printf("CL_ParsePtlCmds: can't get components of a non-vector type (particle %s)\n", name); numPtlCmds--; break; } } /* set the values */ pc->type = pp->type; pc->ref = -((int)pp->ofs); break; } /* get the type */ if (pc_types[i] & PTL_ONLY_ONE_TYPE) /* extract the real type */ j = pc_types[i] & ~PTL_ONLY_ONE_TYPE; else { for (j = 0; j < V_NUM_TYPES; j++) if (Q_streq(token, vt_names[j])) break; if (j >= V_NUM_TYPES || !((1 << j) & pc_types[i])) { Com_Printf("CL_ParsePtlCmds: bad type \"%s\" specified (particle %s)\n", token, name); numPtlCmds--; break; } /* get the value */ token = Com_EParse(text, errhead, name); if (!*text) return; } /* set the values */ pc->type = j; pcmdPos = (byte*) Com_AlignPtr(pcmdPos, (valueTypes_t)pc->type); pc->ref = (int) (pcmdPos - pcmdData); pcmdPos += Com_EParseValue(pcmdPos, token, (valueTypes_t)pc->type, 0, 0); /* Com_Printf("%s %s %i\n", vt_names[pc->type], token, pcmdPos - pc->ref, (char *)pc->ref); */ break; } if (i < PC_NUM_PTLCMDS) continue; for (pp = pps; pp->string; pp++) if (Q_streq(token, pp->string)) { /* get parameter */ token = Com_EParse(text, errhead, name); if (!*text) return; /* translate set to a push and pop */ if (numPtlCmds >= MAX_PTLCMDS - 1) Com_Error(ERR_DROP, "CL_ParsePtlCmds: MAX_PTLCMDS exceeded"); pc = &ptlCmd[numPtlCmds++]; pc->cmd = PC_PUSH; pc->type = pp->type; pcmdPos = (byte*) Com_AlignPtr(pcmdPos, (valueTypes_t)pc->type); pc->ref = (int) (pcmdPos - pcmdData); pcmdPos += Com_EParseValue(pcmdPos, token, (valueTypes_t)pc->type, 0, 0); pc = &ptlCmd[numPtlCmds++]; pc->cmd = PC_POP; pc->type = pp->type; pc->ref = -((int)pp->ofs); break; } if (!pp->string) Com_Printf("CL_ParsePtlCmds: unknown token \"%s\" ignored (particle %s)\n", token, name); } while (*text); /* terminalize cmd chain */ if (numPtlCmds >= MAX_PTLCMDS) Com_Error(ERR_DROP, "CL_ParsePtlCmds: MAX_PTLCMDS exceeded"); pc = &ptlCmd[numPtlCmds++]; OBJZERO(*pc); }