@@ -186,21 +186,13 @@ class parser
186186 char const * const * const argv,
187187 update_notifications version_updates = update_notifications::on,
188188 std::vector<std::string> subcommands = {}) :
189- version_check_dev_decision{version_updates},
190- subcommands{std::move (subcommands)}
189+ argc{argc},
190+ argv{argv},
191+ version_check_dev_decision{version_updates}
191192 {
192- for (auto & sub : this ->subcommands )
193- {
194- if (!std::regex_match (sub, app_name_regex))
195- {
196- throw design_error{" The subcommand name must only contain alpha-numeric characters or '_' and '-' "
197- " (regex: \" ^[a-zA-Z0-9_-]+$\" )." };
198- }
199- }
200-
201193 info.app_name = app_name;
202194
203- init (argc, argv );
195+ add_subcommands ( std::move (subcommands) );
204196 }
205197
206198 // !\brief The destructor.
@@ -666,13 +658,88 @@ class parser
666658 */
667659 parser_meta_data info;
668660
661+ void add_subcommands (std::vector<std::string> const & subcommands)
662+ {
663+ for (auto const & sub : subcommands)
664+ {
665+ if (!std::regex_match (sub, app_name_regex))
666+ {
667+ std::string const error_message =
668+ detail::to_string (std::quoted (info.app_name ),
669+ " contains an invalid subcommand name: " ,
670+ std::quoted (sub),
671+ " . The subcommand name must only contain alpha-numeric characters " ,
672+ " or '_' and '-' (regex: \" ^[a-zA-Z0-9_-]+$\" )." );
673+ throw design_error{error_message};
674+ };
675+ }
676+
677+ auto & parser_subcommands = this ->subcommands ;
678+
679+ #if 0
680+ auto sorted = subcommands;
681+ std::ranges::sort(sorted);
682+ std::vector<std::string> difference{};
683+ std::ranges::set_intersection(sorted, std::ranges::unique(sorted), std::back_inserter(difference));
684+ if (!difference.empty())
685+ {
686+ auto view = std::views::transform(difference,
687+ [](auto const & val)
688+ {
689+ return std::quoted(val);
690+ });
691+ std::string const error_message =
692+ detail::to_string("add_subcommands()'s arguments list contains duplicate elements for ",
693+ std::quoted(info.app_name),
694+ " : ",
695+ view,
696+ ".");
697+ throw design_error{error_message};
698+ }
699+
700+ auto duplicate_subcommands = std::ranges::search(parser_subcommands, subcommands);
701+ if (duplicate_subcommands)
702+ {
703+ auto view = std::views::transform(duplicate_subcommands,
704+ [](auto const & val)
705+ {
706+ return std::quoted(val);
707+ });
708+ std::string const error_message =
709+ detail::to_string(std::quoted(info.app_name), " already contains subcommands: ", view, ".");
710+ throw design_error{error_message};
711+ }
712+ #endif
713+
714+ #ifdef __cpp_lib_containers_ranges
715+ parser_subcommands.append_range (subcommands);
716+ #else
717+ parser_subcommands.insert (parser_subcommands.end (), subcommands.cbegin (), subcommands.cend ());
718+ #endif
719+
720+ std::ranges::sort (parser_subcommands);
721+ auto const [first, last] = std::ranges::unique (parser_subcommands);
722+ parser_subcommands.erase (first, last);
723+
724+ init ();
725+ }
726+
669727private:
670728 // !\brief Keeps track of whether the parse function has been called already.
671729 bool parse_was_called{false };
672730
731+ // !\brief Keeps track of whether the init function has been called already.
732+ bool init_was_called{false };
733+
673734 // !\brief Keeps track of whether the user has added a positional list option to check if this was the very last.
674735 bool has_positional_list_option{false };
675736
737+ // !\brief The number of command line arguments.
738+ int argc{};
739+
740+ // !\brief The command line arguments.
741+ char const * const * argv{nullptr };
742+
676743 // !\brief Set on construction and indicates whether the developer deactivates the version check calls completely.
677744 update_notifications version_check_dev_decision{};
678745
@@ -755,10 +822,19 @@ class parser
755822 *
756823 * If `--export-help` is specified with a value other than html, man, cwl or ctd, an sharg::parser_error is thrown.
757824 */
758- void init (int argc, char const * const * const argv )
825+ void init ()
759826 {
760827 assert (argc > 0 );
761- executable_name.emplace_back (argv[0 ]);
828+
829+ if (init_was_called)
830+ {
831+ cmd_arguments.clear ();
832+ }
833+ else
834+ {
835+ executable_name.emplace_back (argv[0 ]);
836+ init_was_called = true ;
837+ }
762838
763839 bool special_format_was_set{false };
764840
0 commit comments