From ff82c0ade23972f5c02d75359e1343ef7be3b402 Mon Sep 17 00:00:00 2001 From: Kelsi Date: Sat, 9 May 2026 10:22:36 -0700 Subject: [PATCH] refactor(editor): table-driven multi-arg flag validation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Collapse main.cpp's hand-written ladder of 28 individual "if --foo and i+N >= argc, print message, return 1" blocks into a single loop over kMultiArgRequired (struct of flag, needed count, synopsis). main.cpp drops from 246 → 126 lines. Adding a new multi-arg flag now means appending one row to cli_multi_arg_required.cpp instead of pasting another six lines into the validation ladder. Mirrors the kArgRequired pattern that handles single-arg flags. --- CMakeLists.txt | 1 + tools/editor/cli_multi_arg_required.cpp | 49 +++++++++ tools/editor/cli_multi_arg_required.hpp | 30 ++++++ tools/editor/main.cpp | 134 ++---------------------- 4 files changed, 87 insertions(+), 127 deletions(-) create mode 100644 tools/editor/cli_multi_arg_required.cpp create mode 100644 tools/editor/cli_multi_arg_required.hpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e9e19e6e..798a2c57 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1362,6 +1362,7 @@ add_executable(wowee_editor tools/editor/cli_project_actions.cpp tools/editor/cli_zone_export.cpp tools/editor/cli_arg_required.cpp + tools/editor/cli_multi_arg_required.cpp tools/editor/cli_dispatch.cpp tools/editor/editor_app.cpp tools/editor/editor_camera.cpp diff --git a/tools/editor/cli_multi_arg_required.cpp b/tools/editor/cli_multi_arg_required.cpp new file mode 100644 index 00000000..f7c89428 --- /dev/null +++ b/tools/editor/cli_multi_arg_required.cpp @@ -0,0 +1,49 @@ +#include "cli_multi_arg_required.hpp" + +namespace wowee { +namespace editor { +namespace cli { + +const MultiArgFlag kMultiArgRequired[] = { + {"--adt", 3, "--adt requires "}, + {"--diff-zone", 2, "--diff-zone requires "}, + {"--diff-glb", 2, "--diff-glb requires "}, + {"--diff-wom", 2, "--diff-wom requires "}, + {"--diff-wob", 2, "--diff-wob requires "}, + {"--diff-whm", 2, "--diff-whm requires "}, + {"--diff-woc", 2, "--diff-woc requires "}, + {"--diff-jsondbc", 2, "--diff-jsondbc requires "}, + {"--diff-extract", 2, "--diff-extract requires "}, + {"--diff-checksum", 2, "--diff-checksum requires "}, + {"--diff-wcp", 2, "--diff-wcp requires two paths"}, + {"--add-creature", 5, + "--add-creature requires "}, + {"--add-object", 6, + "--add-object requires "}, + {"--add-quest", 2, "--add-quest requires "}, + {"--add-quest-objective", 4, + "--add-quest-objective requires <zoneDir> <questIdx> <type> <targetName>"}, + {"--remove-quest-objective", 3, + "--remove-quest-objective requires <zoneDir> <questIdx> <objIdx>"}, + {"--clone-quest", 2, "--clone-quest requires <zoneDir> <questIdx>"}, + {"--clone-creature", 2, "--clone-creature requires <zoneDir> <idx>"}, + {"--clone-object", 2, "--clone-object requires <zoneDir> <idx>"}, + {"--add-quest-reward-item", 3, + "--add-quest-reward-item requires <zoneDir> <questIdx> <itemPath>"}, + {"--set-quest-reward", 2, + "--set-quest-reward requires <zoneDir> <questIdx> [--xp N] [--gold N] [--silver N] [--copper N]"}, + {"--add-tile", 3, "--add-tile requires <zoneDir> <tx> <ty>"}, + {"--remove-tile", 3, "--remove-tile requires <zoneDir> <tx> <ty>"}, + {"--copy-zone", 2, "--copy-zone requires <srcDir> <newName>"}, + {"--rename-zone", 2, "--rename-zone requires <srcDir> <newName>"}, + {"--remove-creature", 2, "--remove-creature requires <zoneDir> <index>"}, + {"--remove-object", 2, "--remove-object requires <zoneDir> <index>"}, + {"--remove-quest", 2, "--remove-quest requires <zoneDir> <index>"}, +}; + +const std::size_t kMultiArgRequiredSize = + sizeof(kMultiArgRequired) / sizeof(kMultiArgRequired[0]); + +} // namespace cli +} // namespace editor +} // namespace wowee diff --git a/tools/editor/cli_multi_arg_required.hpp b/tools/editor/cli_multi_arg_required.hpp new file mode 100644 index 00000000..b4a2f9c9 --- /dev/null +++ b/tools/editor/cli_multi_arg_required.hpp @@ -0,0 +1,30 @@ +#pragma once + +#include <cstddef> + +namespace wowee { +namespace editor { +namespace cli { + +// Companion to kArgRequired for flags that take MORE than one +// positional argument. main.cpp uses this list for the early +// "missing argument" detector — for each entry we check whether +// argv[i+needed] would run off the end and, if so, print the +// synopsis and exit 1 instead of silently dropping into the GUI. +// +// `needed` is the count of *positional* args after the flag. +// `synopsis` is the full message shown to the user; it should +// embed both the flag and the slot list (e.g. "<zoneDir> <x> <y>") +// so a single std::fprintf reads naturally. +struct MultiArgFlag { + const char* flag; + int needed; + const char* synopsis; +}; + +extern const MultiArgFlag kMultiArgRequired[]; +extern const std::size_t kMultiArgRequiredSize; + +} // namespace cli +} // namespace editor +} // namespace wowee diff --git a/tools/editor/main.cpp b/tools/editor/main.cpp index 1fad0895..b5b7dc40 100644 --- a/tools/editor/main.cpp +++ b/tools/editor/main.cpp @@ -2,6 +2,7 @@ #include "cli_dispatch.hpp" #include "cli_convert_single.hpp" #include "cli_arg_required.hpp" +#include "cli_multi_arg_required.hpp" #include "content_pack.hpp" #include "npc_spawner.hpp" #include "object_placer.hpp" @@ -58,6 +59,8 @@ int main(int argc, char* argv[]) { // Detect non-GUI options that are missing their argument and bail out // with a helpful message instead of silently dropping into the GUI. + // Single-arg flags live in cli_arg_required.{hpp,cpp}; multi-arg flags + // live in cli_multi_arg_required.{hpp,cpp} along with their synopses. for (int i = 1; i < argc; i++) { for (std::size_t k = 0; k < wowee::editor::cli::kArgRequiredSize; ++k) { const char* opt = wowee::editor::cli::kArgRequired[k]; @@ -66,133 +69,10 @@ int main(int argc, char* argv[]) { return 1; } } - if (std::strcmp(argv[i], "--adt") == 0 && i + 3 >= argc) { - std::fprintf(stderr, "--adt requires <map> <x> <y>\n"); - return 1; - } - if (std::strcmp(argv[i], "--diff-zone") == 0 && i + 2 >= argc) { - std::fprintf(stderr, - "--diff-zone requires <zoneA> <zoneB>\n"); - return 1; - } - if (std::strcmp(argv[i], "--diff-glb") == 0 && i + 2 >= argc) { - std::fprintf(stderr, - "--diff-glb requires <a.glb> <b.glb>\n"); - return 1; - } - if (std::strcmp(argv[i], "--diff-wom") == 0 && i + 2 >= argc) { - std::fprintf(stderr, - "--diff-wom requires <a-base> <b-base>\n"); - return 1; - } - if (std::strcmp(argv[i], "--diff-wob") == 0 && i + 2 >= argc) { - std::fprintf(stderr, - "--diff-wob requires <a-base> <b-base>\n"); - return 1; - } - if (std::strcmp(argv[i], "--diff-whm") == 0 && i + 2 >= argc) { - std::fprintf(stderr, - "--diff-whm requires <a-base> <b-base>\n"); - return 1; - } - if (std::strcmp(argv[i], "--diff-woc") == 0 && i + 2 >= argc) { - std::fprintf(stderr, - "--diff-woc requires <a.woc> <b.woc>\n"); - return 1; - } - if (std::strcmp(argv[i], "--diff-jsondbc") == 0 && i + 2 >= argc) { - std::fprintf(stderr, - "--diff-jsondbc requires <a.json> <b.json>\n"); - return 1; - } - if (std::strcmp(argv[i], "--diff-extract") == 0 && i + 2 >= argc) { - std::fprintf(stderr, - "--diff-extract requires <dirA> <dirB>\n"); - return 1; - } - if (std::strcmp(argv[i], "--diff-checksum") == 0 && i + 2 >= argc) { - std::fprintf(stderr, - "--diff-checksum requires <a.sha256> <b.sha256>\n"); - return 1; - } - if (std::strcmp(argv[i], "--diff-wcp") == 0 && i + 2 >= argc) { - std::fprintf(stderr, "--diff-wcp requires two paths\n"); - return 1; - } - if (std::strcmp(argv[i], "--add-creature") == 0 && i + 5 >= argc) { - std::fprintf(stderr, - "--add-creature requires <zoneDir> <name> <x> <y> <z>\n"); - return 1; - } - if (std::strcmp(argv[i], "--add-object") == 0 && i + 6 >= argc) { - std::fprintf(stderr, - "--add-object requires <zoneDir> <m2|wmo> <gamePath> <x> <y> <z>\n"); - return 1; - } - if (std::strcmp(argv[i], "--add-quest") == 0 && i + 2 >= argc) { - std::fprintf(stderr, - "--add-quest requires <zoneDir> <title>\n"); - return 1; - } - if (std::strcmp(argv[i], "--add-quest-objective") == 0 && i + 4 >= argc) { - std::fprintf(stderr, - "--add-quest-objective requires <zoneDir> <questIdx> <type> <targetName>\n"); - return 1; - } - if (std::strcmp(argv[i], "--remove-quest-objective") == 0 && i + 3 >= argc) { - std::fprintf(stderr, - "--remove-quest-objective requires <zoneDir> <questIdx> <objIdx>\n"); - return 1; - } - if (std::strcmp(argv[i], "--clone-quest") == 0 && i + 2 >= argc) { - std::fprintf(stderr, - "--clone-quest requires <zoneDir> <questIdx>\n"); - return 1; - } - if (std::strcmp(argv[i], "--clone-creature") == 0 && i + 2 >= argc) { - std::fprintf(stderr, - "--clone-creature requires <zoneDir> <idx>\n"); - return 1; - } - if (std::strcmp(argv[i], "--clone-object") == 0 && i + 2 >= argc) { - std::fprintf(stderr, - "--clone-object requires <zoneDir> <idx>\n"); - return 1; - } - if (std::strcmp(argv[i], "--add-quest-reward-item") == 0 && i + 3 >= argc) { - std::fprintf(stderr, - "--add-quest-reward-item requires <zoneDir> <questIdx> <itemPath>\n"); - return 1; - } - if (std::strcmp(argv[i], "--set-quest-reward") == 0 && i + 2 >= argc) { - std::fprintf(stderr, - "--set-quest-reward requires <zoneDir> <questIdx> [--xp N] [--gold N] [--silver N] [--copper N]\n"); - return 1; - } - if (std::strcmp(argv[i], "--add-tile") == 0 && i + 3 >= argc) { - std::fprintf(stderr, - "--add-tile requires <zoneDir> <tx> <ty>\n"); - return 1; - } - if (std::strcmp(argv[i], "--remove-tile") == 0 && i + 3 >= argc) { - std::fprintf(stderr, - "--remove-tile requires <zoneDir> <tx> <ty>\n"); - return 1; - } - if (std::strcmp(argv[i], "--copy-zone") == 0 && i + 2 >= argc) { - std::fprintf(stderr, - "--copy-zone requires <srcDir> <newName>\n"); - return 1; - } - if (std::strcmp(argv[i], "--rename-zone") == 0 && i + 2 >= argc) { - std::fprintf(stderr, - "--rename-zone requires <srcDir> <newName>\n"); - return 1; - } - for (const char* opt : {"--remove-creature", "--remove-object", - "--remove-quest"}) { - if (std::strcmp(argv[i], opt) == 0 && i + 2 >= argc) { - std::fprintf(stderr, "%s requires <zoneDir> <index>\n", opt); + for (std::size_t k = 0; k < wowee::editor::cli::kMultiArgRequiredSize; ++k) { + const auto& m = wowee::editor::cli::kMultiArgRequired[k]; + if (std::strcmp(argv[i], m.flag) == 0 && i + m.needed >= argc) { + std::fprintf(stderr, "%s\n", m.synopsis); return 1; } }