parse_config_result metashell::parse_config(int argc_, const char* argv_[], const std::map<std::string, engine_entry>& engines_, iface::environment_detector& env_detector_, std::ostream* out_, std::ostream* err_) { using boost::program_options::options_description; using boost::program_options::variables_map; using boost::program_options::store; using boost::program_options::notify; using boost::program_options::parse_command_line; using boost::program_options::value; data::config cfg; if (argc_ > 0) { cfg.metashell_binary = argv_[0]; } const char** const minus_minus = std::find(argv_, argv_ + argc_, std::string("--")); if (minus_minus != argv_ + argc_) { cfg.extra_clang_args.insert( cfg.extra_clang_args.end(), minus_minus + 1, argv_ + argc_); } const int argc = minus_minus - argv_; std::string con_type("readline"); cfg.use_precompiled_headers = true; std::string help_engine; const std::string engine_info = "The engine (C++ compiler) to use. Available engines: " + boost::algorithm::join(engines_ | boost::adaptors::map_keys, ", ") + ". Default: " + cfg.engine; options_description desc("Options"); // clang-format off desc.add_options() ("help", "Display help") ("verbose,V", "Verbose mode") ("no_highlight,H", "Disable syntax highlighting") ("indent", "Enable indenting (experimental)") ( "no_precompiled_headers", "Disable precompiled header usage." " (It needs clang++ to be available and writes to the local disc.)" ) ( "show_pragma_help", "Display help for pragmas in MarkDown format and exit." ) ( "show_mdb_help", "Display help for mdb commands in MarkDown format and exit" ) ( "disable_saving", "Disable saving the environment using the #msh environment save" ) ( "console", value(&con_type)->default_value(con_type), "Console type. Possible values: plain, readline, json" ) ("nosplash", "Disable the splash messages") ( "log", value(&cfg.log_file), "Log into a file. When it is set to -, it logs into the console." ) ("engine", value(&cfg.engine), engine_info.c_str()) ("help_engine", value(&help_engine), "Display help about the engine") ("preprocessor", "Starts the shell in preprocessor mode"); // clang-format on using dec_arg = decommissioned_argument; using dec_type = decommissioned_argument::type; std::vector<dec_arg> dec_args{ dec_arg{"include", 'I', dec_type::multiple_values}, dec_arg{"define", 'D', dec_type::multiple_values}, dec_arg{"std", dec_type::one_value}, dec_arg{"no_warnings", 'w', dec_type::flag}, dec_arg{'f', dec_type::one_value}, dec_arg{'s', dec_type::one_value}, dec_arg{ "clang", dec_type::one_value, "Please use \"--engine clang\" with the custom clang binary instead.", "{NAME} has been decommissioned. You can specify the clang binary to" " use by using the clang engine. For example:\n" "\n" + std::string(argv_[0]) + " --engine clang -- {VALUE} -std=c++0x -ftemplate-depth=256" " -Wfatal-errors" + (env_detector_.on_windows() ? " -fno-ms-compatibility -U_MSC_VER" : "")}, dec_arg{ "enable_saving", dec_type::flag, "Saving is enabled by default. To disable it, use --disable_saving.", "Saving is enabled by default."}}; for (auto& a : dec_args) { a.add_to(desc); } try { variables_map vm; store(parse_command_line(argc, argv_, desc), vm); notify(vm); for (const auto& a : dec_args) { a.check(vm); } cfg.verbose = vm.count("verbose") || vm.count("V"); cfg.syntax_highlight = !(vm.count("no_highlight") || vm.count("H")); cfg.indent = vm.count("indent") != 0; cfg.con_type = metashell::data::parse_console_type(con_type); cfg.use_precompiled_headers = !vm.count("no_precompiled_headers"); cfg.saving_enabled = !vm.count("disable_saving"); cfg.splash_enabled = vm.count("nosplash") == 0; cfg.preprocessor_mode = vm.count("preprocessor"); if (vm.count("log") == 0) { cfg.log_mode = data::logging_mode::none; } else { cfg.log_mode = (cfg.log_file == "-") ? data::logging_mode::console : data::logging_mode::file; } if (vm.count("help")) { if (out_) { show_help(*out_, desc); } return parse_config_result::exit(false); } else if (vm.count("show_pragma_help")) { show_pragma_help(); return parse_config_result::exit(false); } else if (vm.count("show_mdb_help")) { show_mdb_help(); return parse_config_result::exit(false); } else if (vm.count("help_engine")) { show_engine_help(engines_, help_engine, out_, argv_[0]); return parse_config_result::exit(false); } else { return parse_config_result::start_shell(cfg); } } catch (const std::exception& e_) { if (err_) { *err_ << e_.what() << "\n\n"; show_help(*err_, desc); } return parse_config_result::exit(true); } }