From 2d4017d8e633a02843623eb7fdd94e253a9e3171 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C5=82awomir=20Lach?= Date: Mon, 27 Feb 2023 17:58:10 +0100 Subject: [PATCH] =?UTF-8?q?!OSDN:=20TICKET:=20#45428:=20S=C5=82awomir=20La?= =?UTF-8?q?ch=20?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Duplicated names in ruleset causes error (on load). diff --git a/server/ruleset.c b/server/ruleset.c index 69698bd655..1358885399 100644 --- a/server/ruleset.c +++ b/server/ruleset.c @@ -208,6 +208,12 @@ static bool load_ruleset_veteran(struct section_file *file, char *script_buffer = NULL; char *parser_buffer = NULL; +#define SPECHASH_TAG names_cache +#define SPECHASH_CSTR_KEY_TYPE +#define SPECHASH_CSTR_DATA_TYPE +#include "spechash.h" + + /**********************************************************************//** Notifications about ruleset errors to clients. Especially important in case of internal server crashing. @@ -1249,8 +1255,10 @@ static bool lookup_time(const struct section_file *secfile, int *turns, static bool ruleset_load_names(struct name_translation *pname, const char *domain, struct section_file *file, + struct names_cache_hash *loaded, const char *sec_name) { + char *previos_entry; const char *name = secfile_lookup_str(file, "%s.name", sec_name); const char *rule_name = secfile_lookup_str(file, "%s.rule_name", sec_name); @@ -1261,6 +1269,17 @@ static bool ruleset_load_names(struct name_translation *pname, return FALSE; } + if (NULL != loaded) { + if (names_cache_hash_lookup(loaded, name, &previos_entry)) { + ruleset_error(NULL, LOG_ERROR, + "\"%s\" [%s]: \"name\" field duplicated with \"%s\".", + secfile_name(file), sec_name, previos_entry); + return FALSE; + } + + names_cache_hash_insert(loaded, name, sec_name); + } + names_set(pname, domain, name, rule_name); return TRUE; @@ -1311,6 +1330,7 @@ static void ruleset_load_traits(struct trait_limits *out, static bool load_game_names(struct section_file *file, struct rscompat_info *compat) { + struct names_cache_hash *names_hash; struct section_list *sec; int nval; const char *filename = secfile_name(file); @@ -1339,10 +1359,12 @@ static bool load_game_names(struct section_file *file, } if (ok) { + names_hash = names_cache_hash_new(); achievements_iterate(pach) { const char *sec_name = section_name(section_list_get(sec, achievement_index(pach))); - if (!ruleset_load_names(&pach->name, NULL, file, sec_name)) { + if (!ruleset_load_names(&pach->name, NULL, file, names_hash, + sec_name)) { ruleset_error(NULL, LOG_ERROR, "\"%s\": Cannot load achievement names", filename); @@ -1350,6 +1372,7 @@ static bool load_game_names(struct section_file *file, break; } } achievements_iterate_end; + names_cache_hash_destroy(names_hash); } section_list_destroy(sec); @@ -1377,11 +1400,13 @@ static bool load_game_names(struct section_file *file, } if (ok) { + names_hash = names_cache_hash_new(); goods_type_iterate(pgood) { const char *sec_name = section_name(section_list_get(sec, goods_index(pgood))); - if (!ruleset_load_names(&pgood->name, NULL, file, sec_name)) { + if (!ruleset_load_names(&pgood->name, NULL, file, names_hash, + sec_name)) { ruleset_error(NULL, LOG_ERROR, "\"%s\": Cannot load goods names", filename); @@ -1389,6 +1414,7 @@ static bool load_game_names(struct section_file *file, break; } } goods_type_iterate_end; + names_cache_hash_destroy(names_hash); } section_list_destroy(sec); } @@ -1410,6 +1436,7 @@ static bool load_game_names(struct section_file *file, if (ok) { int count_idx; + names_hash = names_cache_hash_new(); game.control.num_counters = nval; for (count_idx = 0; count_idx < nval; count_idx++) { @@ -1418,7 +1445,8 @@ static bool load_game_names(struct section_file *file, const char *sec_name = section_name(section_list_get(sec, count_idx)); - if (!ruleset_load_names(&pcount->name, NULL, file, sec_name)) { + if (!ruleset_load_names(&pcount->name, NULL, file, names_hash, + sec_name)) { ruleset_error(NULL, LOG_ERROR, "\"%s\": Cannot load counters names", filename); @@ -1461,6 +1489,7 @@ static bool load_action_names(struct section_file *file, static bool load_tech_names(struct section_file *file, struct rscompat_info *compat) { + struct names_cache_hash *names_hash; struct section_list *sec = NULL; /* Number of techs in the ruleset (means without A_NONE). */ int num_techs = 0; @@ -1523,11 +1552,13 @@ static bool load_tech_names(struct section_file *file, } if (ok) { + names_hash = names_cache_hash_new(); tech_class_iterate(ptclass) { const char *sec_name = section_name(section_list_get(sec, tech_class_index(ptclass))); - if (!ruleset_load_names(&ptclass->name, NULL, file, sec_name)) { + if (!ruleset_load_names(&ptclass->name, NULL, file, names_hash, + sec_name)) { ruleset_error(NULL, LOG_ERROR, "\"%s\": Cannot load tech class names", filename); ok = FALSE; @@ -1535,6 +1566,7 @@ static bool load_tech_names(struct section_file *file, } } tech_class_iterate_end; } + names_cache_hash_destroy(names_hash); } if (ok) { @@ -1556,17 +1588,19 @@ static bool load_tech_names(struct section_file *file, } if (ok) { + names_hash = names_cache_hash_new(); game.control.num_tech_types = num_techs + A_FIRST; /* includes A_NONE */ i = 0; advance_iterate(adv) { - if (!ruleset_load_names(&adv->name, NULL, file, + if (!ruleset_load_names(&adv->name, NULL, file, names_hash, section_name(section_list_get(sec, i)))) { ok = FALSE; break; } i++; } advance_iterate_end; + names_cache_hash_destroy(names_hash); } section_list_destroy(sec); @@ -1790,6 +1824,7 @@ restart: static bool load_unit_names(struct section_file *file, struct rscompat_info *compat) { + struct names_cache_hash *names_hash; struct section_list *sec = NULL; int nval = 0; int i; @@ -1892,17 +1927,19 @@ static bool load_unit_names(struct section_file *file, } if (ok) { + names_hash = names_cache_hash_new(); game.control.num_unit_classes = nval; unit_class_iterate(punitclass) { const int pci = uclass_index(punitclass); - if (!ruleset_load_names(&punitclass->name, NULL, file, + if (!ruleset_load_names(&punitclass->name, NULL, file, names_hash, section_name(section_list_get(sec, pci)))) { ok = FALSE; break; } } unit_class_iterate_end; + names_cache_hash_destroy(names_hash); } section_list_destroy(sec); sec = NULL; @@ -1926,16 +1963,18 @@ static bool load_unit_names(struct section_file *file, } if (ok) { + names_hash = names_cache_hash_new(); game.control.num_unit_types = nval; unit_type_iterate(punittype) { const int utypei = utype_index(punittype); - if (!ruleset_load_names(&punittype->name, NULL, file, + if (!ruleset_load_names(&punittype->name, NULL, file, names_hash, section_name(section_list_get(sec, utypei)))) { ok = FALSE; break; } } unit_type_iterate_end; + names_cache_hash_destroy(names_hash); } section_list_destroy(sec); @@ -2547,6 +2586,7 @@ static bool load_ruleset_units(struct section_file *file, static bool load_building_names(struct section_file *file, struct rscompat_info *compat) { + struct names_cache_hash *names_hash; struct section_list *sec; int i, nval = 0; const char *filename = secfile_name(file); @@ -2577,16 +2617,19 @@ static bool load_building_names(struct section_file *file, } if (ok) { + names_hash = names_cache_hash_new(); game.control.num_impr_types = nval; for (i = 0; i < nval; i++) { struct impr_type *b = improvement_by_number(i); - if (!ruleset_load_names(&b->name, NULL, file, section_name(section_list_get(sec, i)))) { + if (!ruleset_load_names(&b->name, NULL, file, names_hash, + section_name(section_list_get(sec, i)))) { ok = FALSE; break; } } + names_cache_hash_destroy(names_hash); } /* User building flag names */ @@ -2746,6 +2789,7 @@ static bool load_ruleset_buildings(struct section_file *file, static bool load_terrain_names(struct section_file *file, struct rscompat_info *compat) { + struct names_cache_hash *names_hash; int nval = 0; struct section_list *sec = NULL; const char *flag; @@ -2845,6 +2889,7 @@ static bool load_terrain_names(struct section_file *file, } if (ok) { + names_hash = names_cache_hash_new(); game.control.terrain_count = nval; /* avoid re-reading files */ @@ -2857,13 +2902,15 @@ static bool load_terrain_names(struct section_file *file, const int terri = terrain_index(pterrain); const char *sec_name = section_name(section_list_get(sec, terri)); - if (!ruleset_load_names(&pterrain->name, NULL, file, sec_name)) { + if (!ruleset_load_names(&pterrain->name, NULL, file, names_hash, + sec_name)) { ok = FALSE; break; } section_strlcpy(&terrain_sections[terri * MAX_SECTION_LABEL], sec_name); } terrain_type_iterate_end; + names_cache_hash_destroy(names_hash); } section_list_destroy(sec); @@ -2885,6 +2932,7 @@ static bool load_terrain_names(struct section_file *file, if (ok) { int idx; + names_hash = names_cache_hash_new(); game.control.num_extra_types = nval; if (extra_sections) { @@ -2897,13 +2945,15 @@ static bool load_terrain_names(struct section_file *file, const char *sec_name = section_name(section_list_get(sec, idx)); struct extra_type *pextra = extra_by_number(idx); - if (!ruleset_load_names(&pextra->name, NULL, file, sec_name)) { + if (!ruleset_load_names(&pextra->name, NULL, file, names_hash, + sec_name)) { ok = FALSE; break; } section_strlcpy(&extra_sections[idx * MAX_SECTION_LABEL], sec_name); } } + names_cache_hash_destroy(names_hash); } section_list_destroy(sec); @@ -4218,6 +4268,7 @@ static bool load_ruleset_terrain(struct section_file *file, static bool load_government_names(struct section_file *file, struct rscompat_info *compat) { + struct names_cache_hash *names_hash; int nval = 0; struct section_list *sec; const char *filename = secfile_name(file); @@ -4242,6 +4293,7 @@ static bool load_government_names(struct section_file *file, } if (ok) { + names_hash = names_cache_hash_new(); governments_alloc(nval); /* Government names are needed early so that get_government_by_name will @@ -4250,11 +4302,13 @@ static bool load_government_names(struct section_file *file, const char *sec_name = section_name(section_list_get(sec, government_index(gov))); - if (!ruleset_load_names(&gov->name, NULL, file, sec_name)) { + if (!ruleset_load_names(&gov->name, NULL, file,names_hash, + sec_name)) { ok = FALSE; break; } } governments_iterate_end; + names_cache_hash_destroy(names_hash); } section_list_destroy(sec); @@ -4274,11 +4328,13 @@ static bool load_government_names(struct section_file *file, } if (ok) { + names_hash = names_cache_hash_new(); multipliers_iterate(pmul) { const char *sec_name = section_name(section_list_get(sec, multiplier_index(pmul))); - if (!ruleset_load_names(&pmul->name, NULL, file, sec_name)) { + if (!ruleset_load_names(&pmul->name, NULL, file, names_hash, + sec_name)) { ruleset_error(NULL, LOG_ERROR, "\"%s\": Cannot load multiplier names", filename); @@ -4286,6 +4342,7 @@ static bool load_government_names(struct section_file *file, break; } } multipliers_iterate_end; + names_cache_hash_destroy(names_hash); } } @@ -4550,6 +4607,7 @@ static const char *check_leader_names(struct nation_type *pnation) static bool load_nation_names(struct section_file *file, struct rscompat_info *compat) { + struct names_cache_hash *names_hash; struct section_list *sec; int j; bool ok = TRUE; @@ -4575,6 +4633,7 @@ static bool load_nation_names(struct section_file *file, } else { game.control.nation_count = section_list_size(sec); nations_alloc(game.control.nation_count); + names_hash = names_cache_hash_new(); nations_iterate(pl) { const int i = nation_index(pl); @@ -4584,7 +4643,6 @@ static bool load_nation_names(struct section_file *file, const char *noun_plural = secfile_lookup_str(file, "%s.plural", sec_name); - if (domain == NULL) { domain = "freeciv-nations"; } @@ -4601,7 +4659,8 @@ static bool load_nation_names(struct section_file *file, break; } - if (!ruleset_load_names(&pl->adjective, pl->translation_domain, file, sec_name)) { + if (!ruleset_load_names(&pl->adjective, pl->translation_domain, file, names_hash, + sec_name)) { ok = FALSE; break; } @@ -4647,6 +4706,7 @@ static bool load_nation_names(struct section_file *file, break; } } nations_iterate_end; + names_cache_hash_destroy(names_hash); } section_list_destroy(sec); @@ -5589,6 +5649,7 @@ static bool load_ruleset_nations(struct section_file *file, static bool load_style_names(struct section_file *file, struct rscompat_info *compat) { + struct names_cache_hash *names_hash; bool ok = TRUE; struct section_list *sec; const char *filename = secfile_name(file); @@ -5606,6 +5667,7 @@ static bool load_style_names(struct section_file *file, "No available nation styles in this ruleset!"); ok = FALSE; } else { + names_hash = names_cache_hash_new(); game.control.num_styles = section_list_size(sec); styles_alloc(game.control.num_styles); @@ -5614,8 +5676,9 @@ static bool load_style_names(struct section_file *file, const int i = style_index(ps); const char *sec_name = section_name(section_list_get(sec, i)); - ruleset_load_names(&ps->name, NULL, file, sec_name); + ruleset_load_names(&ps->name, NULL, file, names_hash,sec_name); } styles_iterate_end; + names_cache_hash_destroy(names_hash); } section_list_destroy(sec); @@ -5624,16 +5687,20 @@ static bool load_style_names(struct section_file *file, /* The citystyle sections: */ int i = 0; + names_hash = names_cache_hash_new(); + sec = secfile_sections_by_name_prefix(file, CITYSTYLE_SECTION_PREFIX); if (NULL != sec) { city_styles_alloc(section_list_size(sec)); section_list_iterate(sec, style) { - if (!ruleset_load_names(&city_styles[i].name, NULL, file, section_name(style))) { + if (!ruleset_load_names(&city_styles[i].name, NULL, file, names_hash, + section_name(style))) { ok = FALSE; break; } i++; } section_list_iterate_end; + names_cache_hash_destroy(names_hash); section_list_destroy(sec); } else { @@ -5829,6 +5896,7 @@ static bool load_muuk_as_action_auto(struct section_file *file, static bool load_ruleset_cities(struct section_file *file, struct rscompat_info *compat) { + struct names_cache_hash *names_hash; const char *filename = secfile_name(file); const char *item; struct section_list *sec; @@ -5854,6 +5922,8 @@ static bool load_ruleset_cities(struct section_file *file, int i = 0; const char *tag; + names_hash = names_cache_hash_new(); + game.control.num_specialist_types = section_list_size(sec); section_list_iterate(sec, psection) { @@ -5861,7 +5931,8 @@ static bool load_ruleset_cities(struct section_file *file, struct requirement_vector *reqs; const char *sec_name = section_name(psection); - if (!ruleset_load_names(&s->name, NULL, file, sec_name)) { + if (!ruleset_load_names(&s->name, NULL, file, names_hash, + sec_name)) { ok = FALSE; break; } @@ -5897,6 +5968,8 @@ static bool load_ruleset_cities(struct section_file *file, } i++; } section_list_iterate_end; + + names_cache_hash_destroy(names_hash); } if (ok && DEFAULT_SPECIALIST == -1) { @@ -6483,6 +6556,7 @@ static bool lookup_bv_actions(struct section_file *file, static bool load_ruleset_game(struct section_file *file, bool act, struct rscompat_info *compat) { + struct names_cache_hash *names_hash; const char *sval, **svec; const char *filename; int *food_ini; @@ -7190,6 +7264,7 @@ static bool load_ruleset_game(struct section_file *file, bool act, } if (ok) { + names_hash = names_cache_hash_new(); disaster_type_iterate(pdis) { int id = disaster_index(pdis); int j; @@ -7197,7 +7272,8 @@ static bool load_ruleset_game(struct section_file *file, bool act, struct requirement_vector *reqs; const char *sec_name = section_name(section_list_get(sec, id)); - if (!ruleset_load_names(&pdis->name, NULL, file, sec_name)) { + if (!ruleset_load_names(&pdis->name, NULL, file, names_hash, + sec_name)) { ruleset_error(NULL, LOG_ERROR, "\"%s\": Cannot load disaster names", filename); @@ -7241,6 +7317,7 @@ static bool load_ruleset_game(struct section_file *file, bool act, break; } } disaster_type_iterate_end; + names_cache_hash_destroy(names_hash); section_list_destroy(sec); } @@ -7475,6 +7552,8 @@ static bool load_ruleset_game(struct section_file *file, bool act, int num = section_list_size(sec); int curr; + names_hash = names_cache_hash_new(); + for (curr = 0; curr < num; curr++) { struct counter *pcount = counter_by_id(curr); @@ -7493,7 +7572,8 @@ static bool load_ruleset_game(struct section_file *file, bool act, break; } - if (!ruleset_load_names(&pcount->name, NULL, file, sec_name)) { + if (!ruleset_load_names(&pcount->name, NULL, file, names_hash, + sec_name)) { ruleset_error(NULL, LOG_ERROR, "\"%s\": Cannot load counter names", filename); @@ -7519,6 +7599,7 @@ static bool load_ruleset_game(struct section_file *file, bool act, sec_name); attach_city_counter(pcount); } + names_cache_hash_destroy(names_hash); } } -- 2.39.2