/** * @brief Copies an entry from the building description file into the list of building types. * @note Parses one "building" entry in the basemanagement.ufo file and writes * it into the next free entry in bmBuildings[0], which is the list of buildings * in the first base (building_t). * @param[in] name Unique script id of a building. This is parsed from "building xxx" -> id=xxx. * @param[in] text the whole following text that is part of the "building" item definition in .ufo. * @param[in] link Bool value that decides whether to link the tech pointer in or not * @sa CL_ParseScriptFirst (link is false here) * @sa CL_ParseScriptSecond (link it true here) */ void B_ParseBuildings (const char *name, const char **text, qboolean link) { building_t *building; technology_t *techLink; const char *errhead = "B_ParseBuildings: unexpected end of file (names "; const char *token; /* get id list body */ token = Com_Parse(text); if (!*text || *token != '{') { Com_Printf("B_ParseBuildings: building \"%s\" without body ignored\n", name); return; } if (ccs.numBuildingTemplates >= MAX_BUILDINGS) Com_Error(ERR_DROP, "B_ParseBuildings: too many buildings"); if (!link) { int i; for (i = 0; i < ccs.numBuildingTemplates; i++) { if (Q_streq(ccs.buildingTemplates[i].id, name)) { Com_Printf("B_ParseBuildings: Second building with same name found (%s) - second ignored\n", name); return; } } /* new entry */ building = &ccs.buildingTemplates[ccs.numBuildingTemplates]; OBJZERO(*building); building->id = Mem_PoolStrDup(name, cp_campaignPool, 0); Com_DPrintf(DEBUG_CLIENT, "...found building %s\n", building->id); /* set standard values */ building->tpl = building; /* Self-link just in case ... this way we can check if it is a template or not. */ building->idx = -1; /* No entry in buildings list (yet). */ building->base = NULL; building->buildingType = MAX_BUILDING_TYPE; building->dependsBuilding = NULL; building->maxCount = -1; /* Default: no limit */ building->size[0] = 1; building->size[1] = 1; ccs.numBuildingTemplates++; do { /* get the name type */ token = Com_EParse(text, errhead, name); if (!*text) break; if (*token == '}') break; /* get values */ if (Q_streq(token, "type")) { token = Com_EParse(text, errhead, name); if (!*text) return; building->buildingType = B_GetBuildingTypeByBuildingID(token); if (building->buildingType >= MAX_BUILDING_TYPE) Com_Printf("didn't find buildingType '%s'\n", token); } else { /* no linking yet */ if (Q_streq(token, "depends")) { token = Com_EParse(text, errhead, name); if (!*text) return; } else { if (!Com_ParseBlockToken(name, text, building, valid_building_vars, cp_campaignPool, token)) Com_Printf("B_ParseBuildings: unknown token \"%s\" ignored (building %s)\n", token, name); } } } while (*text); if (building->size[0] < 1 || building->size[1] < 1 || building->size[0] >= BASE_SIZE || building->size[1] >= BASE_SIZE) { Com_Printf("B_ParseBuildings: Invalid size for building %s (%i, %i)\n", building->id, (int)building->size[0], (int)building->size[1]); ccs.numBuildingTemplates--; } } else { building = B_GetBuildingTemplate(name); if (!building) Com_Error(ERR_DROP, "B_ParseBuildings: Could not find building with id %s\n", name); techLink = RS_GetTechByProvided(name); if (techLink) building->tech = techLink; do { /* get the name type */ token = Com_EParse(text, errhead, name); if (!*text) break; if (*token == '}') break; /* get values */ if (Q_streq(token, "depends")) { const building_t *dependsBuilding = B_GetBuildingTemplate(Com_EParse(text, errhead, name)); if (!dependsBuilding) Com_Error(ERR_DROP, "Could not find building depend of %s\n", building->id); building->dependsBuilding = dependsBuilding; if (!*text) return; } } while (*text); } }
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); }
/** * @brief Parses particle definitions from UFO-script files * @param[in] name particle name/id * @param[in] text pointer to the buffer to parse from * @return the position of the particle in ptlDef array * @sa CL_ParseClientData */ void CL_ParseParticle (const char *name, const char **text) { const char *errhead = "CL_ParseParticle: unexpected end of file (particle "; ptlDef_t *pd; const char *token; int i; /* search for particles with same name */ for (i = 0; i < numPtlDefs; i++) if (Q_streq(name, ptlDef[i].name)) break; if (i < numPtlDefs) { Com_Printf("CL_ParseParticle: particle def \"%s\" with same name found, reset first one\n", name); pd = &ptlDef[i]; } else { if (numPtlDefs < MAX_PTLDEFS - 1) { /* initialize the new particle */ pd = &ptlDef[numPtlDefs++]; } else { Com_Printf("CL_ParseParticle: max particle definitions reached - skip the current one: '%s'\n", name); return; } } OBJZERO(*pd); Q_strncpyz(pd->name, name, sizeof(pd->name)); /* get it's body */ token = Com_Parse(text); if (!*text || *token != '{') { Com_Printf("CL_ParseParticle: particle def \"%s\" without body ignored\n", name); if (i == numPtlDefs) numPtlDefs--; return; } do { token = Com_EParse(text, errhead, name); if (!*text) break; if (*token == '}') break; for (i = 0; i < PF_NUM_PTLFUNCS; i++) if (Q_streq(token, pf_strings[i])) { /* allocate the first particle command */ ptlCmd_t **pc; pc = (ptlCmd_t **) ((byte *) pd + pf_values[i]); *pc = &ptlCmd[numPtlCmds]; /* parse the commands */ CL_ParsePtlCmds(name, text); break; } if (i == PF_NUM_PTLFUNCS) Com_Printf("CL_ParseParticle: unknown token \"%s\" ignored (particle %s)\n", token, name); } while (*text); /* check for an init function */ if (!pd->init) { Com_Printf("CL_ParseParticle: particle definition %s without init function ignored\n", name); if (i == numPtlDefs) numPtlDefs--; } }
/** * @brief Read a node body * @note Node header already read, we are over the node name, or '{' * @code * Allowed syntax * { properties } * OR * { nodes } * OR * { { properties } nodes } * @endcode */ static bool UI_ParseNodeBody (uiNode_t *node, const char **text, const char **token, const char *errhead) { bool result = true; if ((*token)[0] != '{') { /* read the body block start */ *token = Com_EParse(text, errhead, node->name); if (!*text) return false; if ((*token)[0] != '{') { Com_Printf("UI_ParseNodeBody: node doesn't have body, token '%s' read (node \"%s\")\n", *token, UI_GetPath(node)); ui_global.numNodes--; return false; } } /* functions are a special case */ if (UI_Node_IsFunction(node)) { result = UI_ParseFunction(node, text, token); } else { /* check the content */ *token = Com_EParse(text, errhead, node->name); if (!*text) return false; if ((*token)[0] == '{') { /* we have a special block for properties */ result = UI_ParseNodeProperties(node, text, token); if (!result) return false; /* move token over the next node behaviour */ *token = Com_EParse(text, errhead, node->name); if (!*text) return false; /* and then read all nodes */ while ((*token)[0] != '}') { uiNode_t *newNode = UI_ParseNode(node, text, token, errhead); if (!newNode) return false; *token = Com_EParse(text, errhead, node->name); if (*text == nullptr) return false; } } else if (UI_GetPropertyFromBehaviour(node->behaviour, *token)) { /* we should have a block with properties only */ result = UI_ParseNodeProperties(node, text, token); } else { /* we should have a block with nodes only */ while ((*token)[0] != '}') { uiNode_t *newNode = UI_ParseNode(node, text, token, errhead); if (!newNode) return false; *token = Com_EParse(text, errhead, node->name); if (*text == nullptr) return false; } } } if (!result) { Com_Printf("UI_ParseNodeBody: node with bad body ignored (node \"%s\")\n", UI_GetPath(node)); ui_global.numNodes--; return false; } /* already check on UI_ParseNodeProperties */ assert((*token)[0] == '}'); return true; }
/** * @brief Reads the sequence values from given text-pointer * @sa CL_ParseClientData */ void CL_ParseSequence (const char* name, const char** text) { const char* errhead = "CL_ParseSequence: unexpected end of file (sequence "; int i; /* search for sequences with same name */ for (i = 0; i < numSequences; i++) if (Q_streq(name, sequences[i].name)) break; if (i < numSequences) { Com_Printf("CL_ParseSequence: sequence def \"%s\" with same name found, second ignored\n", name); return; } /* initialize the sequence */ if (numSequences >= MAX_SEQUENCES) Com_Error(ERR_FATAL, "Too many sequences"); sequence_t* sp = &sequences[numSequences++]; OBJZERO(*sp); Q_strncpyz(sp->name, name, sizeof(sp->name)); sp->start = numSeqCmds; /* get it's body */ const char* token = Com_Parse(text); if (!*text || *token != '{') { Com_Printf("CL_ParseSequence: sequence def \"%s\" without body ignored\n", name); numSequences--; return; } do { token = Com_EParse(text, errhead, name); if (!*text) break; if (*token == '}') break; /* check for commands */ int i = CL_FindSequenceCommand(token); if (i != -1) { int maxLength = MAX_DATA_LENGTH; char* data; /* found a command */ token = Com_EParse(text, errhead, name); if (!*text) return; if (numSeqCmds >= MAX_SEQCMDS) Com_Error(ERR_FATAL, "Too many sequence commands for %s\n", name); /* init seqCmd */ if (seqCmds == nullptr) seqCmds = Mem_PoolAllocTypeN(seqCmd_t, MAX_SEQCMDS, cl_genericPool); seqCmd_t* sc = &seqCmds[numSeqCmds++]; OBJZERO(*sc); sc->handler = seqCmdFunc[i]; sp->length++; /* copy name */ Q_strncpyz(sc->name, token, sizeof(sc->name)); /* read data */ token = Com_EParse(text, errhead, name); if (!*text) return; if (*token == '{') { // TODO depth is useless IMHO (bayo) int depth = 1; data = &sc->data[0]; while (depth) { if (maxLength <= 0) { Com_Printf("Too much data for sequence %s\n", sc->name); break; } token = Com_EParse(text, errhead, name); if (!*text) return; if (*token == '{') depth++; else if (*token == '}') depth--; if (depth) { Q_strncpyz(data, token, maxLength); data += strlen(token) + 1; maxLength -= (strlen(token) + 1); } } } else if (*token == '(') { linkedList_t* list; Com_UnParseLastToken(); if (!Com_ParseList(text, &list)) { Com_Error(ERR_DROP, "CL_ParseSequence: error while reading list (sequence \"%s\")", name); } data = &sc->data[0]; for (linkedList_t* element = list; element != nullptr; element = element->next) { if (maxLength <= 0) { Com_Printf("Too much data for sequence %s", sc->name); break; } const char* v = (char*)element->data; Q_strncpyz(data, v, maxLength); data += strlen(v) + 1; maxLength -= (strlen(v) + 1); } LIST_Delete(&list); } else { Com_UnParseLastToken(); } } else { Com_Printf("CL_ParseSequence: unknown command \"%s\" ignored (sequence %s)\n", token, name); Com_EParse(text, errhead, name); } } while (*text); }
/** * @brief Parse actions and return action list * @return The first element from a list of action * @sa ea_t * @todo need cleanup, compute action out of the final memory; reduce number of var */ static uiAction_t *UI_ParseActionList (uiNode_t *node, const char **text, const char **token) { const char *errhead = "UI_ParseActionList: unexpected end of file (in event)"; uiAction_t *firstAction; uiAction_t *lastAction; uiAction_t *action; lastAction = nullptr; firstAction = nullptr; /* prevent bad position */ if ((*token)[0] != '{') { Com_Printf("UI_ParseActionList: token \"{\" expected, but \"%s\" found (in event) (node: %s)\n", *token, UI_GetPath(node)); return nullptr; } while (true) { bool result; int type = EA_NULL; /* get new token */ *token = Com_EParse(text, errhead, nullptr); if (!*token) return nullptr; if ((*token)[0] == '}') break; type = UI_GetActionTokenType(*token, EA_ACTION); /* setter form */ if (type == EA_NULL && (*token)[0] == '*') type = EA_ASSIGN; /* unknown, we break the parsing */ if (type == EA_NULL) { Com_Printf("UI_ParseActionList: unknown token \"%s\" ignored (in event) (node: %s)\n", *token, UI_GetPath(node)); return nullptr; } /* add the action */ action = UI_AllocStaticAction(); /** @todo better to append the action after initialization */ if (lastAction) lastAction->next = action; if (!firstAction) firstAction = action; action->type = type; /* decode action */ switch (action->type) { case EA_CMD: /* get parameter values */ *token = Com_EParse(text, errhead, nullptr); if (!*text) return nullptr; /* get the value */ action->d.terminal.d1.constString = UI_AllocStaticString(*token, 0); break; case EA_ASSIGN: result = UI_ParseSetAction(node, action, text, token, errhead); if (!result) return nullptr; break; case EA_CALL: result = UI_ParseCallAction(node, action, text, token, errhead); if (!result) return nullptr; break; case EA_DELETE: { uiAction_t *expression; expression = UI_ParseExpression(text); if (expression == nullptr) return nullptr; if (expression->type != EA_VALUE_CVARNAME) { Com_Printf("UI_ParseActionList: \"delete\" keyword only support cvarname (node: %s)\n", UI_GetPath(node)); return nullptr; } action->d.nonTerminal.left = expression; break; } case EA_ELIF: /* check previous action */ if (!lastAction || (lastAction->type != EA_IF && lastAction->type != EA_ELIF)) { Com_Printf("UI_ParseActionList: 'elif' must be set after an 'if' or an 'elif' (node: %s)\n", UI_GetPath(node)); return nullptr; } /* then it execute EA_IF, no break */ case EA_WHILE: case EA_IF: { uiAction_t *expression; /* get the condition */ expression = UI_ParseExpression(text); if (expression == nullptr) return nullptr; action->d.nonTerminal.left = expression; /* get the action block */ *token = Com_EParse(text, errhead, nullptr); if (!*text) return nullptr; action->d.nonTerminal.right = UI_ParseActionList(node, text, token); if (action->d.nonTerminal.right == nullptr) { if (action->type == EA_IF) Com_Printf("UI_ParseActionList: block expected after \"if\" (node: %s)\n", UI_GetPath(node)); else if (action->type == EA_ELIF) Com_Printf("UI_ParseActionList: block expected after \"elif\" (node: %s)\n", UI_GetPath(node)); else Com_Printf("UI_ParseActionList: block expected after \"while\" (node: %s)\n", UI_GetPath(node)); return nullptr; } break; } case EA_ELSE: /* check previous action */ if (!lastAction || (lastAction->type != EA_IF && lastAction->type != EA_ELIF)) { Com_Printf("UI_ParseActionList: 'else' must be set after an 'if' or an 'elif' (node: %s)\n", UI_GetPath(node)); return nullptr; } /* get the action block */ *token = Com_EParse(text, errhead, nullptr); if (!*text) return nullptr; action->d.nonTerminal.left = nullptr; action->d.nonTerminal.right = UI_ParseActionList(node, text, token); if (action->d.nonTerminal.right == nullptr) { Com_Printf("UI_ParseActionList: block expected after \"else\" (node: %s)\n", UI_GetPath(node)); return nullptr; } break; default: assert(false); } /* step */ lastAction = action; } assert((*token)[0] == '}'); /* return non nullptr value */ if (firstAction == nullptr) { firstAction = UI_AllocStaticAction(); } return firstAction; }
/** * @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; }
/** * @brief Parse a component * @sa CL_ParseClientData * @code * component panel componentName { * } * @endcode */ bool UI_ParseComponent (const char *type, const char *name, const char **text) { const char *errhead = "UI_ParseComponent: unexpected end of file (component"; const char *token; if (!Q_streq(type, "component")) { Com_Error(ERR_FATAL, "UI_ParseComponent: \"component\" expected but \"%s\" found.\n", type); return false; /* never reached */ } /* check the name */ if (!UI_TokenIsName(name, false)) { Com_Printf("UI_ParseNode: \"%s\" is not a well formed node name ([a-zA-Z_][a-zA-Z0-9_]*)\n", name); return false; } if (UI_TokenIsReserved(name)) { Com_Printf("UI_ParseNode: \"%s\" is a reserved token, we can't call a node with it\n", name); return false; } token = Com_EParse(text, errhead, ""); if (text == nullptr) return false; /* get keyword */ if (!Q_streq(token, "extends")) { Com_Printf("UI_ParseComponent: \"extends\" expected but \"%s\" found (component %s)\n", token, name); return false; } token = Com_EParse(text, errhead, ""); if (text == nullptr) return false; /* initialize component */ uiNode_t *component = nullptr; const uiBehaviour_t *behaviour = UI_GetNodeBehaviour(token); if (behaviour) { /* initialize a new node from behaviour */ component = UI_AllocNode(name, behaviour->name, false); } else { const uiNode_t *inheritedComponent = UI_GetComponent(token); if (inheritedComponent) { /* initialize from a component */ component = UI_CloneNode(inheritedComponent, nullptr, true, name, false); } else { Com_Printf("UI_ParseComponent: node behaviour/component '%s' doesn't exists (component %s)\n", token, name); return false; } } /* get body */ token = Com_EParse(text, errhead, ""); if (!*text) return false; bool result = UI_ParseNodeBody(component, text, &token, errhead); if (!result) return false; /* validate properties */ UI_Node_Loaded(component); UI_InsertComponent(component); return true; }
/** * @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 parses the models.ufo and all files where UI models (menu_model) are defined * @sa CL_ParseClientData */ bool UI_ParseUIModel (const char *name, const char **text) { uiModel_t *model; const char *token; int i; const char *errhead = "UI_ParseUIModel: unexpected end of file (names "; /* search for a UI models with same name */ for (i = 0; i < ui_global.numModels; i++) if (Q_streq(ui_global.models[i].id, name)) { Com_Printf("UI_ParseUIModel: menu_model \"%s\" with same name found, second ignored\n", name); return false; } if (ui_global.numModels >= UI_MAX_MODELS) { Com_Printf("UI_ParseUIModel: Max UI models reached\n"); return false; } /* initialize the model */ model = &ui_global.models[ui_global.numModels]; OBJZERO(*model); Vector4Set(model->color, 1, 1, 1, 1); model->id = Mem_PoolStrDup(name, ui_sysPool, 0); Com_DPrintf(DEBUG_CLIENT, "Found UI model %s (%i)\n", model->id, ui_global.numModels); /* get it's body */ token = Com_Parse(text); if (!*text || token[0] != '{') { Com_Printf("UI_ParseUIModel: Model \"%s\" without body ignored\n", model->id); return false; } ui_global.numModels++; do { const value_t *v = nullptr; /* get the name type */ token = Com_EParse(text, errhead, name); if (!*text) return false; if (token[0] == '}') break; v = UI_FindPropertyByName(uiModelProperties, token); if (!v) { Com_Printf("UI_ParseUIModel: unknown token \"%s\" ignored (UI model %s)\n", token, name); return false; } if (v->type == V_NULL) { if (Q_streq(v->string, "need")) { token = Com_EParse(text, errhead, name); if (!*text) return false; if (model->next != nullptr) Sys_Error("UI_ParseUIModel: second 'need' token found in model %s", name); model->next = UI_GetUIModel(token); if (!model->next) Com_Printf("Could not find UI model %s", token); } } else { token = Com_EParse(text, errhead, name); if (!*text) return false; switch (v->type) { case V_HUNK_STRING: Mem_PoolStrDupTo(token, &Com_GetValue<char*>(model, v), ui_sysPool, 0); break; default: Com_EParseValue(model, token, v->type, v->ofs, v->size); break; } } } while (*text); return true; }
/** * @brief parse a node * @sa UI_ParseNodeProperties * @todo we can think about merging UI_ParseNodeProperties here * @note first token already read * @note dont read more than the need token (last right token is '}' of end of node) */ static uiNode_t *UI_ParseNode (uiNode_t *parent, const char **text, const char **token, const char *errhead) { uiNode_t *node = nullptr; uiBehaviour_t *behaviour; uiNode_t *component = nullptr; /* get the behaviour */ behaviour = UI_GetNodeBehaviour(*token); if (!behaviour) { component = UI_GetComponent(*token); } if (behaviour == nullptr && component == nullptr) { Com_Printf("UI_ParseNode: node behaviour/component '%s' doesn't exists (%s)\n", *token, UI_GetPath(parent)); return nullptr; } /* get the name */ *token = Com_EParse(text, errhead, ""); if (!*text) return nullptr; if (!UI_TokenIsName(*token, Com_GetType(text) == TT_QUOTED_WORD)) { Com_Printf("UI_ParseNode: \"%s\" is not a well formed node name ([a-zA-Z_][a-zA-Z0-9_]*)\n", *token); return nullptr; } if (UI_TokenIsReserved(*token)) { Com_Printf("UI_ParseNode: \"%s\" is a reserved token, we can't call a node with it\n", *token); return nullptr; } /* test if node already exists */ /* Already existing node should only come from inherited node,we should not have 2 definitions of the same node into the same window. */ if (parent) node = UI_GetNode(parent, *token); /* reuse a node */ if (node) { if (node->behaviour != behaviour) { Com_Printf("UI_ParseNode: we can't change node type (node \"%s\")\n", UI_GetPath(node)); return nullptr; } Com_DPrintf(DEBUG_CLIENT, "... over-riding node %s\n", UI_GetPath(node)); /* else initialize a component */ } else if (component) { node = UI_CloneNode(component, nullptr, true, *token, false); if (parent) { if (parent->root) UI_UpdateRoot(node, parent->root); UI_AppendNode(parent, node); } /* else initialize a new node */ } else { node = UI_AllocNode(*token, behaviour->name, false); node->parent = parent; if (parent) node->root = parent->root; /** @todo move it into caller */ if (parent) UI_AppendNode(parent, node); } /* get body */ const bool result = UI_ParseNodeBody(node, text, token, errhead); if (!result) return nullptr; /* validate properties */ UI_Node_Loaded(node); return node; }
static void SCP_ParseMission (const char *name, const char **text) { const char *errhead = "SCP_ParseMission: unexpected end of file (mission "; staticMission_t *ms; const value_t *vp; const char *token; int i; size_t writtenBytes; token = Com_Parse(text); if (token[0] == '\0' || text[0] == '\0') { Com_Printf("SCP_ParseMission: mission def \"%s\" without name ignored\n", name); return; } /* search for missions with same name */ for (i = 0; i < scd->numMissions; i++) if (Q_streq(token, scd->missions[i].id)) break; if (i < scd->numMissions) { Com_Printf("SCP_ParseMission: mission def \"%s\" with same name found, second ignored\n", token); return; } if (scd->numMissions >= MAX_STATIC_MISSIONS) { Com_Printf("SCP_ParseMission: Too many missions, ignore '%s'\n", token); return; } /* initialize the menu */ ms = &scd->missions[scd->numMissions]; OBJZERO(*ms); Q_strncpyz(ms->id, token, sizeof(ms->id)); /* get it's body */ token = Com_Parse(text); if (text[0] == '\0' || !Q_streq(token, "{")) { Com_Printf("SCP_ParseMission: mission def \"%s\" without body ignored\n", ms->id); return; } do { token = Com_EParse(text, errhead, ms->id); if (text[0] == '\0') break; if (token[0] == '}') break; for (vp = mission_vals; vp->string; vp++) if (Q_streq(token, vp->string)) { /* found a definition */ token = Com_EParse(text, errhead, ms->id); if (text[0] == '\0') return; if (vp->ofs) { Com_ParseValue(ms, token, vp->type, vp->ofs, vp->size, &writtenBytes); } else { Com_Printf("SCP_ParseMission: unknown token '%s'\n", token); } break; } if (!vp->string) { if (Q_streq(token, "city")) { const city_t *city; token = Com_EParse(text, errhead, ms->id); if (text[0] == '\0') return; city = CP_GetCity(token); if (city == NULL) Com_Printf("SCP_ParseMission: unknown city \"%s\" ignored (mission %s)\n", token, ms->id); else Vector2Copy(city->pos, ms->pos); } else { Com_Printf("SCP_ParseMission: unknown token \"%s\" ignored (mission %s)\n", token, ms->id); } } } while (*text); mapDef_t *mapDef = cgi->Com_GetMapDefinitionByID(ms->id); if (mapDef == NULL) { Com_Printf("SCP_ParseMission: invalid mapdef for '%s'\n", ms->id); return; } if (Vector2Empty(ms->pos)) { if (!CP_GetRandomPosOnGeoscapeWithParameters(ms->pos, mapDef->terrains, mapDef->cultures, mapDef->populations, NULL)) { Com_Printf("SCP_ParseMission: could not find a valid position for '%s'\n", ms->id); return; } } scd->numMissions++; }
static void SCP_ParseStageSet (const char *name, const char **text) { const char *errhead = "SCP_ParseStageSet: unexpected end of file (stageset "; stageSet_t *sp; const value_t *vp; char missionstr[256]; const char *token, *misp; int j; size_t writtenBytes; /* initialize the stage */ sp = &scd->stageSets[scd->numStageSets++]; OBJZERO(*sp); Q_strncpyz(sp->name, name, sizeof(sp->name)); /* get it's body */ token = Com_Parse(text); if (text[0] == '\0' || !Q_streq(token, "{")) { Com_Printf("SCP_ParseStageSet: stageset def \"%s\" without body ignored\n", sp->name); scd->numStageSets--; return; } do { token = Com_EParse(text, errhead, sp->name); if (!*text) break; if (token[0] == '}') break; /* check for some standard values */ for (vp = stageset_vals; vp->string; vp++) if (Q_streq(token, vp->string)) { /* found a definition */ token = Com_EParse(text, errhead, sp->name); if (!*text) return; Com_ParseValue(sp, token, vp->type, vp->ofs, vp->size, &writtenBytes); break; } if (vp->string) continue; /* get mission set */ if (Q_streq(token, "missions")) { token = Com_EParse(text, errhead, sp->name); if (!*text) return; Q_strncpyz(missionstr, token, sizeof(missionstr)); misp = missionstr; /* add mission options */ sp->numMissions = 0; do { token = Com_Parse(&misp); if (!misp) break; for (j = 0; j < scd->numMissions; j++) { if (Q_streq(token, scd->missions[j].id)) { sp->missions[sp->numMissions++] = j; break; } } if (j == scd->numMissions) { const mapDef_t *mapDef = cgi->Com_GetMapDefinitionByID(token); if (mapDef != NULL) { if (j < MAX_STATIC_MISSIONS - 1) { /* we don't need and mission definition in the scripts if we just would like to link a mapdef */ staticMission_t *mis = &scd->missions[j]; OBJZERO(*mis); Q_strncpyz(mis->id, token, sizeof(mis->id)); if (!CP_GetRandomPosOnGeoscapeWithParameters(mis->pos, mapDef->terrains, mapDef->cultures, mapDef->populations, NULL)) { Com_Printf("SCP_ParseMission: could not find a valid position for '%s'\n", mis->id); continue; } sp->missions[sp->numMissions++] = scd->numMissions++; } } else { Com_Printf("SCP_ParseStageSet: unknown mission \"%s\" ignored (stageset %s)\n", token, sp->name); } } } while (misp && sp->numMissions < MAX_SETMISSIONS); continue; } Com_Printf("SCP_ParseStageSet: unknown token \"%s\" ignored (stageset %s)\n", token, sp->name); } while (*text); }
/** * @brief Copies an entry from the installation description file into the list of installation templates. * @note Parses one "installation" entry in the installation.ufo file and writes * it into the next free entry in installationTemplates. * @param[in] name Unique test-id of a installationTemplate_t. * @param[in] text the rest of the script file that is tokenized here */ void INS_ParseInstallations (const char *name, const char **text) { installationTemplate_t *installation; const char *errhead = "INS_ParseInstallations: unexpected end of file (names "; const char *token; int i; /* get id list body */ token = Com_Parse(text); if (!*text || *token != '{') { Com_Printf("INS_ParseInstallations: installation \"%s\" without body ignored\n", name); return; } if (!name) { Com_Printf("INS_ParseInstallations: installation name not specified.\n"); return; } if (ccs.numInstallationTemplates >= MAX_INSTALLATION_TEMPLATES) { Com_Printf("INS_ParseInstallations: too many installation templates\n"); ccs.numInstallationTemplates = MAX_INSTALLATION_TEMPLATES; /* just in case it's bigger. */ return; } for (i = 0; i < ccs.numInstallationTemplates; i++) { if (Q_streq(ccs.installationTemplates[i].name, name)) { Com_Printf("INS_ParseInstallations: Second installation with same name found (%s) - second ignored\n", name); return; } } /* new entry */ installation = &ccs.installationTemplates[ccs.numInstallationTemplates]; OBJZERO(*installation); installation->id = Mem_PoolStrDup(name, cp_campaignPool, 0); Com_DPrintf(DEBUG_CLIENT, "...found installation %s\n", installation->id); ccs.numInstallationTemplates++; do { /* get the name type */ token = Com_EParse(text, errhead, name); if (!*text) break; if (*token == '}') break; /* check for some standard values */ if (!Com_ParseBlockToken(name, text, installation, installation_vals, cp_campaignPool, token)) { /* other values */ if (Q_streq(token, "cost")) { char cvarname[MAX_VAR] = "mn_installation_"; Q_strcat(cvarname, installation->id, sizeof(cvarname)); Q_strcat(cvarname, "_cost", sizeof(cvarname)); token = Com_EParse(text, errhead, name); if (!*text) return; installation->cost = atoi(token); Cvar_Set(cvarname, va(_("%d c"), atoi(token))); } else if (Q_streq(token, "buildtime")) { char cvarname[MAX_VAR]; token = Com_EParse(text, errhead, name); if (!*text) return; installation->buildTime = atoi(token); Com_sprintf(cvarname, sizeof(cvarname), "mn_installation_%s_buildtime", installation->id); Cvar_Set(cvarname, va(ngettext("%d day", "%d days", atoi(token)), atoi(token))); } } } while (*text); }