/** * @brief unittest to check well formed empty list */ TEST_F(ParserTest, ParserListOkEmpty) { const char* string = " ( \n ) ()"; const char* cursor = string; linkedList_t* list; ASSERT_TRUE(Com_ParseList(&cursor, &list)) << "List parsing failed"; ASSERT_EQ(LIST_Count(list), 0); ASSERT_TRUE(Com_ParseList(&cursor, &list)) << "List parsing failed"; ASSERT_EQ(LIST_Count(list), 0); }
/** * @brief unittest to check wrong list which contains another sublist */ TEST_F(ParserTest, ParserListKoNewList) { const char* string = " ( aaa \n bbb \t ccc \n \n ( "; const char* cursor = string; linkedList_t* list; ASSERT_FALSE(Com_ParseList(&cursor, &list)) << "List parsing succeed, which is wrong"; }
/** * @brief Parses music definitions for different situations * @note We have lists for geoscape, battlescape, main and aircombat */ void M_ParseMusic (const char* name, const char** text) { int i; if (Q_streq(name, "geoscape")) i = MUSIC_GEOSCAPE; else if (Q_streq(name, "battlescape")) i = MUSIC_BATTLESCAPE; else if (Q_streq(name, "aircombat")) i = MUSIC_AIRCOMBAT; else if (Q_streq(name, "main")) i = MUSIC_MAIN; else { Com_Printf("M_ParseMusic: Invalid music id '%s'!\n", name); linkedList_t* list; Com_ParseList(text, &list); LIST_Delete(&list); return; } /* get it's body */ linkedList_t* list; if (!Com_ParseList(text, &list)) { Com_Error(ERR_DROP, "M_ParseMusic: error while reading music \"%s\"", name); } for (linkedList_t* element = list; element != nullptr; element = element->next) { if (musicArrayLength[i] >= MUSIC_MAX_ENTRIES) { Com_Printf("M_ParseMusic: Too many music entries for category: '%s'!\n", name); break; } musicArrays[i][musicArrayLength[i]] = Mem_PoolStrDup((char*)element->data, cl_genericPool, 0); musicArrayLength[i]++; } LIST_Delete(&list); }
/** * @brief unittest to check well formed list */ TEST_F(ParserTest, ParserListOk) { const char* string = " ( aaa \n \"bbb\" \t ccc \n \n ) "; const char* cursor = string; linkedList_t* list; ASSERT_TRUE(Com_ParseList(&cursor, &list)) << "List parsing failed"; ASSERT_EQ(LIST_Count(list), 3); ASSERT_STREQ(static_cast<const char*>(list->data), "aaa"); ASSERT_STREQ(static_cast<const char*>(list->next->data), "bbb"); ASSERT_STREQ(static_cast<const char*>(list->next->next->data), "ccc"); LIST_Delete(&list); }
/** * @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 "; sequence_t *sp; const char *token; 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"); sp = &sequences[numSequences++]; OBJZERO(*sp); Q_strncpyz(sp->name, name, sizeof(sp->name)); sp->start = numSeqCmds; /* get it's body */ 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; seqCmd_t *sc; /* 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", name); /* init seqCmd */ if (seqCmds == NULL) seqCmds = Mem_PoolAllocTypeN(seqCmd_t, MAX_SEQCMDS, cl_genericPool); 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", 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 != NULL; 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 all language definitions from the script files */ void CL_ParseLanguages (const char* name, const char** text) { const char* errhead = "CL_ParseLanguages: unexpected end of file (language "; const char* token; if (!*text) { Com_Printf("CL_ParseLanguages: language without body ignored (%s)\n", name); return; } token = Com_EParse(text, errhead, name); if (!*text || *token != '{') { Com_Printf("CL_ParseLanguages: language without body ignored (%s)\n", name); return; } language_t* const language = Mem_PoolAllocType(language_t, cl_genericPool); language->localeID = Mem_PoolStrDup(name, cl_genericPool, 0); language->localeString = ""; language->nativeString = ""; language->localeMapping = nullptr; do { /* get the name type */ token = Com_EParse(text, errhead, name); if (!*text || *token == '}') break; /* inner locale id definition */ if (Q_streq(token, "code")) { linkedList_t* list; if (!Com_ParseList(text, &list)) { Com_Error(ERR_DROP, "CL_ParseLanguages: error while reading language codes \"%s\"", name); } for (linkedList_t* element = list; element != nullptr; element = element->next) { localeMapping_t* const mapping = Mem_PoolAllocType(localeMapping_t, cl_genericPool); mapping->localeMapping = Mem_PoolStrDup((char*)element->data, cl_genericPool, 0); /* link it in */ mapping->next = language->localeMapping; language->localeMapping = mapping; } LIST_Delete(&list); } else if (Q_streq(token, "name")) { token = Com_EParse(text, errhead, name); if (!*text || *token == '}') Com_Error(ERR_FATAL, "CL_ParseLanguages: Name expected for language \"%s\".\n", name); if (*token != '_') { Com_Printf("CL_ParseLanguages: language: '%s' - not marked translatable (%s)\n", name, token); } language->localeString = Mem_PoolStrDup(token, cl_genericPool, 0); } else if (Q_streq(token, "native")) { token = Com_EParse(text, errhead, name); if (!*text || *token == '}') Com_Error(ERR_FATAL, "CL_ParseLanguages: Native expected for language \"%s\".\n", name); language->nativeString = Mem_PoolStrDup(token, cl_genericPool, 0); } } while (*text); language->next = languageList; languageList = language; languageCount++; }
/** * @sa CL_ParseScriptFirst */ static void CP_ParseAlienTeam (const char *name, const char **text) { const char *errhead = "CP_ParseAlienTeam: unexpected end of file (alienteam "; const char *token; int i; alienTeamCategory_t *alienCategory; /* get it's body */ token = Com_Parse(text); if (!*text || *token != '{') { Com_Printf("CP_ParseAlienTeam: alien team category \"%s\" without body ignored\n", name); return; } if (ccs.numAlienCategories >= ALIENCATEGORY_MAX) { Com_Printf("CP_ParseAlienTeam: maximum number of alien team category reached (%i)\n", ALIENCATEGORY_MAX); return; } /* search for category with same name */ for (i = 0; i < ccs.numAlienCategories; i++) if (Q_streq(name, ccs.alienCategories[i].id)) break; if (i < ccs.numAlienCategories) { Com_Printf("CP_ParseAlienTeam: alien category def \"%s\" with same name found, second ignored\n", name); return; } alienCategory = &ccs.alienCategories[ccs.numAlienCategories++]; Q_strncpyz(alienCategory->id, name, sizeof(alienCategory->id)); do { token = cgi->Com_EParse(text, errhead, name); if (!*text) break; if (*token == '}') break; if (Q_streq(token, "equipment")) { linkedList_t **list = &alienCategory->equipment; if (!Com_ParseList(text, list)) { cgi->Com_Error(ERR_DROP, "CL_ParseAlienTeam: \"%s\" Error while parsing equipment list", name); } } else if (Q_streq(token, "category")) { linkedList_t *list; if (!Com_ParseList(text, &list)) { cgi->Com_Error(ERR_DROP, "CL_ParseAlienTeam: \"%s\" Error while parsing category list", name); } for (linkedList_t *element = list; element != NULL; element = element->next) { alienCategory->missionCategories[alienCategory->numMissionCategories] = CP_GetAlienMissionTypeByID((char*)element->data); if (alienCategory->missionCategories[alienCategory->numMissionCategories] == INTERESTCATEGORY_NONE) Com_Printf("CP_ParseAlienTeam: alien team category \"%s\" is used with no mission category. It won't be used in game.\n", name); alienCategory->numMissionCategories++; } LIST_Delete(&list); } else if (Q_streq(token, "teaminterest")) { alienTeamGroup_t *group; token = cgi->Com_EParse(text, errhead, name); if (!*text || *token != '{') { Com_Printf("CP_ParseAlienTeam: alien team \"%s\" has team with no opening brace\n", name); break; } if (alienCategory->numAlienTeamGroups >= MAX_ALIEN_GROUP_PER_CATEGORY) { Com_Printf("CP_ParseAlienTeam: maximum number of alien team reached (%i) in category \"%s\"\n", MAX_ALIEN_GROUP_PER_CATEGORY, name); break; } group = &alienCategory->alienTeamGroups[alienCategory->numAlienTeamGroups]; group->idx = alienCategory->numAlienTeamGroups; group->categoryIdx = alienCategory - ccs.alienCategories; alienCategory->numAlienTeamGroups++; do { token = cgi->Com_EParse(text, errhead, name); if (!Com_ParseBlockToken(name, text, group, alien_group_vals, cp_campaignPool, token)) { const teamDef_t *teamDef; if (!*text || *token == '}') break; if (Q_streq(token, "team")) { linkedList_t *list; if (!Com_ParseList(text, &list)) { cgi->Com_Error(ERR_DROP, "CL_ParseAlienTeam: \"%s\" Error while parsing team list", name); } for (linkedList_t *element = list; element != NULL; element = element->next) { if (group->numAlienTeams >= MAX_TEAMS_PER_MISSION) cgi->Com_Error(ERR_DROP, "CL_ParseAlienTeam: MAX_TEAMS_PER_MISSION hit"); teamDef = cgi->Com_GetTeamDefinitionByID((char*)element->data); if (teamDef) group->alienTeams[group->numAlienTeams++] = teamDef; } LIST_Delete(&list); } else { cgi->Com_Error(ERR_DROP, "CL_ParseAlienTeam: Unknown token \"%s\"\n", token); } } } while (*text); } else { Com_Printf("CP_ParseAlienTeam: unknown token \"%s\" ignored (category %s)\n", token, name); continue; } } while (*text); if (LIST_IsEmpty(alienCategory->equipment)) Sys_Error("alien category equipment list is empty"); }