From ae0198ea0aab580d4a29f91cd71651de8a4c0b9a Mon Sep 17 00:00:00 2001 From: wmayer Date: Mon, 8 Nov 2021 11:10:13 +0100 Subject: [PATCH] App: split Application::ParseOptions into two functions to simplify handling of options that should be processed before determining user directories --- src/App/Application.cpp | 658 ++++++++++++++++++++-------------------- src/App/Application.h | 2 - 2 files changed, 331 insertions(+), 329 deletions(-) diff --git a/src/App/Application.cpp b/src/App/Application.cpp index faac993af3..d47e10666e 100644 --- a/src/App/Application.cpp +++ b/src/App/Application.cpp @@ -2009,6 +2009,332 @@ void Application::initTypes(void) new ExceptionProducer; } +namespace { +pair customSyntax(const string& s) +{ +#if defined(FC_OS_MACOSX) + if (s.find("-psn_") == 0) + return make_pair(string("psn"), s.substr(5)); +#endif + if (s.find("-display") == 0) + return make_pair(string("display"), string("null")); + else if (s.find("-style") == 0) + return make_pair(string("style"), string("null")); + else if (s.find("-graphicssystem") == 0) + return make_pair(string("graphicssystem"), string("null")); + else if (s.find("-widgetcount") == 0) + return make_pair(string("widgetcount"), string("")); + else if (s.find("-geometry") == 0) + return make_pair(string("geometry"), string("null")); + else if (s.find("-font") == 0) + return make_pair(string("font"), string("null")); + else if (s.find("-fn") == 0) + return make_pair(string("fn"), string("null")); + else if (s.find("-background") == 0) + return make_pair(string("background"), string("null")); + else if (s.find("-bg") == 0) + return make_pair(string("bg"), string("null")); + else if (s.find("-foreground") == 0) + return make_pair(string("foreground"), string("null")); + else if (s.find("-fg") == 0) + return make_pair(string("fg"), string("null")); + else if (s.find("-button") == 0) + return make_pair(string("button"), string("null")); + else if (s.find("-btn") == 0) + return make_pair(string("btn"), string("null")); + else if (s.find("-name") == 0) + return make_pair(string("name"), string("null")); + else if (s.find("-title") == 0) + return make_pair(string("title"), string("null")); + else if (s.find("-visual") == 0) + return make_pair(string("visual"), string("null")); +// else if (s.find("-ncols") == 0) +// return make_pair(string("ncols"), boost::program_options::value(1)); +// else if (s.find("-cmap") == 0) +// return make_pair(string("cmap"), string("null")); + else if ('@' == s[0]) + return std::make_pair(string("response-file"), s.substr(1)); + else + return make_pair(string(), string()); +} + +void parseProgramOptions(int ac, char ** av, const string& exe, variables_map& vm) +{ + // Declare a group of options that will be + // allowed only on the command line + options_description generic("Generic options"); + generic.add_options() + ("version,v", "Prints version string") + ("help,h", "Prints help message") + ("console,c", "Starts in console mode") + ("response-file", value(),"Can be specified with '@name', too") + ("dump-config", "Dumps configuration") + ("get-config", value(), "Prints the value of the requested configuration key") + ; + + // Declare a group of options that will be + // allowed both on the command line and in + // the config file + std::stringstream descr; + descr << "Writes " << exe << ".log to the user directory."; + boost::program_options::options_description config("Configuration"); + config.add_options() + //("write-log,l", value(), "write a log file") + ("write-log,l", descr.str().c_str()) + ("log-file", value(), "Unlike --write-log this allows logging to an arbitrary file") + ("user-cfg,u", value(),"User config file to load/save user settings") + ("system-cfg,s", value(),"System config file to load/save system settings") + ("run-test,t", value() ,"Test case - or 0 for all") + ("module-path,M", value< vector >()->composing(),"Additional module paths") + ("python-path,P", value< vector >()->composing(),"Additional python paths") + ("single-instance", "Allow to run a single instance of the application") + ; + + + // Hidden options, will be allowed both on the command line and + // in the config file, but will not be shown to the user. + boost::program_options::options_description hidden("Hidden options"); + hidden.add_options() + ("input-file", boost::program_options::value< vector >(), "input file") + ("output", boost::program_options::value(),"output file") + ("hidden", "don't show the main window") + // this are to ignore for the window system (QApplication) + ("style", boost::program_options::value< string >(), "set the application GUI style") + ("stylesheet", boost::program_options::value< string >(), "set the application stylesheet") + ("session", boost::program_options::value< string >(), "restore the application from an earlier session") + ("reverse", "set the application's layout direction from right to left") + ("widgetcount", "print debug messages about widgets") + ("graphicssystem", boost::program_options::value< string >(), "backend to be used for on-screen widgets and pixmaps") + ("display", boost::program_options::value< string >(), "set the X-Server") + ("geometry ", boost::program_options::value< string >(), "set the X-Window geometry") + ("font", boost::program_options::value< string >(), "set the X-Window font") + ("fn", boost::program_options::value< string >(), "set the X-Window font") + ("background", boost::program_options::value< string >(), "set the X-Window background color") + ("bg", boost::program_options::value< string >(), "set the X-Window background color") + ("foreground", boost::program_options::value< string >(), "set the X-Window foreground color") + ("fg", boost::program_options::value< string >(), "set the X-Window foreground color") + ("button", boost::program_options::value< string >(), "set the X-Window button color") + ("btn", boost::program_options::value< string >(), "set the X-Window button color") + ("name", boost::program_options::value< string >(), "set the X-Window name") + ("title", boost::program_options::value< string >(), "set the X-Window title") + ("visual", boost::program_options::value< string >(), "set the X-Window to color scheme") + ("ncols", boost::program_options::value< int >(), "set the X-Window to color scheme") + ("cmap", "set the X-Window to color scheme") +#if defined(FC_OS_MACOSX) + ("psn", boost::program_options::value< string >(), "process serial number") +#endif + ; + + // Ignored options, will be safely ignored. Mostly used by underlying libs. + //boost::program_options::options_description x11("X11 options"); + //x11.add_options() + // ("display", boost::program_options::value< string >(), "set the X-Server") + // ; + //0000723: improper handling of qt specific command line arguments + std::vector args; + bool merge=false; + for (int i=1; i().c_str()); + if (!ifs) { + Base::Console().Error("Could no open the response file\n"); + std::stringstream str; + str << "Could no open the response file: '" + << vm["response-file"].as() << "'" << endl; + throw Base::UnknownProgramOption(str.str()); + } + // Read the whole file into a string + stringstream ss; + ss << ifs.rdbuf(); + // Split the file content + char_separator sep(" \n\r"); + tokenizer > tok(ss.str(), sep); + vector args; + copy(tok.begin(), tok.end(), back_inserter(args)); + // Parse the file and store the options + store( boost::program_options::command_line_parser(args). + options(cmdline_options).positional(p).extra_parser(customSyntax).run(), vm); + } +} + +void processProgramOptions(const variables_map& vm, std::map& mConfig) +{ + if (vm.count("version")) { + std::stringstream str; + str << mConfig["ExeName"] << " " << mConfig["ExeVersion"] + << " Revision: " << mConfig["BuildRevision"] << std::endl; + throw Base::ProgramInformation(str.str()); + } + + if (vm.count("console")) { + mConfig["Console"] = "1"; + mConfig["RunMode"] = "Cmd"; + } + + if (vm.count("module-path")) { + vector Mods = vm["module-path"].as< vector >(); + string temp; + for (vector::const_iterator It= Mods.begin();It != Mods.end();++It) + temp += *It + ";"; + temp.erase(temp.end()-1); + mConfig["AdditionalModulePaths"] = temp; + } + + if (vm.count("python-path")) { + vector Paths = vm["python-path"].as< vector >(); + for (vector::const_iterator It= Paths.begin();It != Paths.end();++It) + Base::Interpreter().addPythonPath(It->c_str()); + } + + if (vm.count("input-file")) { + vector files(vm["input-file"].as< vector >()); + int OpenFileCount=0; + for (vector::const_iterator It = files.begin();It != files.end();++It) { + + //cout << "Input files are: " + // << vm["input-file"].as< vector >() << "\n"; + + std::ostringstream temp; + temp << "OpenFile" << OpenFileCount; + mConfig[temp.str()] = *It; + OpenFileCount++; + } + std::ostringstream buffer; + buffer << OpenFileCount; + mConfig["OpenFileCount"] = buffer.str(); + } + + if (vm.count("output")) { + string file = vm["output"].as(); + mConfig["SaveFile"] = file; + } + + if (vm.count("hidden")) { + mConfig["StartHidden"] = "1"; + } + + if (vm.count("write-log")) { + mConfig["LoggingFile"] = "1"; + //mConfig["LoggingFileName"] = vm["write-log"].as(); + mConfig["LoggingFileName"] = mConfig["UserAppData"] + mConfig["ExeName"] + ".log"; + } + + if (vm.count("log-file")) { + mConfig["LoggingFile"] = "1"; + mConfig["LoggingFileName"] = vm["log-file"].as(); + } + + if (vm.count("user-cfg")) { + mConfig["UserParameter"] = vm["user-cfg"].as(); + } + + if (vm.count("system-cfg")) { + mConfig["SystemParameter"] = vm["system-cfg"].as(); + } + + if (vm.count("run-test")) { + string testCase = vm["run-test"].as(); + if ( "0" == testCase) { + testCase = "TestApp.All"; + } + mConfig["TestCase"] = testCase; + mConfig["RunMode"] = "Internal"; + mConfig["ScriptFileName"] = "FreeCADTest"; + //sScriptName = FreeCADTest; + } + + if (vm.count("single-instance")) { + mConfig["SingleInstance"] = "1"; + } + + if (vm.count("dump-config")) { + std::stringstream str; + for (std::map::iterator it=mConfig.begin(); it != mConfig.end(); ++it) { + str << it->first << "=" << it->second << std::endl; + } + throw Base::ProgramInformation(str.str()); + } + + if (vm.count("get-config")) { + std::string configKey = vm["get-config"].as(); + std::stringstream str; + std::map::iterator pos; + pos = mConfig.find(configKey); + if (pos != mConfig.end()) { + str << pos->second; + } + str << std::endl; + throw Base::ProgramInformation(str.str()); + } +} +} + void Application::initConfig(int argc, char ** argv) { // find the home path.... @@ -2047,6 +2373,9 @@ void Application::initConfig(int argc, char ** argv) } } + variables_map vm; + parseProgramOptions(argc, argv, mConfig["ExeName"], vm); + // extract home paths ExtractUserPath(); @@ -2065,8 +2394,8 @@ void Application::initConfig(int argc, char ** argv) else Base::Console().Warning("Encoding of Python paths failed\n"); - // Parse the options that have impact on the init process - ParseOptions(argc,argv); + // Handle the options that have impact on the init process + processProgramOptions(vm, mConfig); // Init console =========================================================== Base::PyGILStateLocker lock; @@ -2470,55 +2799,6 @@ namespace boost { namespace program_options { } } #endif -pair customSyntax(const string& s) -{ -#if defined(FC_OS_MACOSX) - if (s.find("-psn_") == 0) - return make_pair(string("psn"), s.substr(5)); -#endif - if (s.find("-display") == 0) - return make_pair(string("display"), string("null")); - else if (s.find("-style") == 0) - return make_pair(string("style"), string("null")); - else if (s.find("-graphicssystem") == 0) - return make_pair(string("graphicssystem"), string("null")); - else if (s.find("-widgetcount") == 0) - return make_pair(string("widgetcount"), string("")); - else if (s.find("-geometry") == 0) - return make_pair(string("geometry"), string("null")); - else if (s.find("-font") == 0) - return make_pair(string("font"), string("null")); - else if (s.find("-fn") == 0) - return make_pair(string("fn"), string("null")); - else if (s.find("-background") == 0) - return make_pair(string("background"), string("null")); - else if (s.find("-bg") == 0) - return make_pair(string("bg"), string("null")); - else if (s.find("-foreground") == 0) - return make_pair(string("foreground"), string("null")); - else if (s.find("-fg") == 0) - return make_pair(string("fg"), string("null")); - else if (s.find("-button") == 0) - return make_pair(string("button"), string("null")); - else if (s.find("-btn") == 0) - return make_pair(string("btn"), string("null")); - else if (s.find("-name") == 0) - return make_pair(string("name"), string("null")); - else if (s.find("-title") == 0) - return make_pair(string("title"), string("null")); - else if (s.find("-visual") == 0) - return make_pair(string("visual"), string("null")); -// else if (s.find("-ncols") == 0) -// return make_pair(string("ncols"), boost::program_options::value(1)); -// else if (s.find("-cmap") == 0) -// return make_pair(string("cmap"), string("null")); - else if ('@' == s[0]) - return std::make_pair(string("response-file"), s.substr(1)); - else - return make_pair(string(), string()); - -} - // A helper function to simplify the main part. template ostream& operator<<(ostream& os, const vector& v) @@ -2527,282 +2807,6 @@ ostream& operator<<(ostream& os, const vector& v) return os; } -void Application::ParseOptions(int ac, char ** av) -{ - // Declare a group of options that will be - // allowed only on the command line - options_description generic("Generic options"); - generic.add_options() - ("version,v", "Prints version string") - ("help,h", "Prints help message") - ("console,c", "Starts in console mode") - ("response-file", value(),"Can be specified with '@name', too") - ("dump-config", "Dumps configuration") - ("get-config", value(), "Prints the value of the requested configuration key") - ; - - // Declare a group of options that will be - // allowed both on the command line and in - // the config file - std::string descr("Writes a log file to:\n"); - descr += mConfig["UserAppData"]; - descr += mConfig["ExeName"]; - descr += ".log"; - boost::program_options::options_description config("Configuration"); - config.add_options() - //("write-log,l", value(), "write a log file") - ("write-log,l", descr.c_str()) - ("log-file", value(), "Unlike --write-log this allows logging to an arbitrary file") - ("user-cfg,u", value(),"User config file to load/save user settings") - ("system-cfg,s", value(),"System config file to load/save system settings") - ("run-test,t", value() ,"Test case - or 0 for all") - ("module-path,M", value< vector >()->composing(),"Additional module paths") - ("python-path,P", value< vector >()->composing(),"Additional python paths") - ("single-instance", "Allow to run a single instance of the application") - ; - - - // Hidden options, will be allowed both on the command line and - // in the config file, but will not be shown to the user. - boost::program_options::options_description hidden("Hidden options"); - hidden.add_options() - ("input-file", boost::program_options::value< vector >(), "input file") - ("output", boost::program_options::value(),"output file") - ("hidden", "don't show the main window") - // this are to ignore for the window system (QApplication) - ("style", boost::program_options::value< string >(), "set the application GUI style") - ("stylesheet", boost::program_options::value< string >(), "set the application stylesheet") - ("session", boost::program_options::value< string >(), "restore the application from an earlier session") - ("reverse", "set the application's layout direction from right to left") - ("widgetcount", "print debug messages about widgets") - ("graphicssystem", boost::program_options::value< string >(), "backend to be used for on-screen widgets and pixmaps") - ("display", boost::program_options::value< string >(), "set the X-Server") - ("geometry ", boost::program_options::value< string >(), "set the X-Window geometry") - ("font", boost::program_options::value< string >(), "set the X-Window font") - ("fn", boost::program_options::value< string >(), "set the X-Window font") - ("background", boost::program_options::value< string >(), "set the X-Window background color") - ("bg", boost::program_options::value< string >(), "set the X-Window background color") - ("foreground", boost::program_options::value< string >(), "set the X-Window foreground color") - ("fg", boost::program_options::value< string >(), "set the X-Window foreground color") - ("button", boost::program_options::value< string >(), "set the X-Window button color") - ("btn", boost::program_options::value< string >(), "set the X-Window button color") - ("name", boost::program_options::value< string >(), "set the X-Window name") - ("title", boost::program_options::value< string >(), "set the X-Window title") - ("visual", boost::program_options::value< string >(), "set the X-Window to color scheme") - ("ncols", boost::program_options::value< int >(), "set the X-Window to color scheme") - ("cmap", "set the X-Window to color scheme") -#if defined(FC_OS_MACOSX) - ("psn", boost::program_options::value< string >(), "process serial number") -#endif - ; - - // Ignored options, will be safely ignored. Mostly used by underlying libs. - //boost::program_options::options_description x11("X11 options"); - //x11.add_options() - // ("display", boost::program_options::value< string >(), "set the X-Server") - // ; - //0000723: improper handling of qt specific command line arguments - std::vector args; - bool merge=false; - for (int i=1; i().c_str()); - if (!ifs) { - Base::Console().Error("Could no open the response file\n"); - std::stringstream str; - str << "Could no open the response file: '" - << vm["response-file"].as() << "'" << endl; - throw Base::UnknownProgramOption(str.str()); - } - // Read the whole file into a string - stringstream ss; - ss << ifs.rdbuf(); - // Split the file content - char_separator sep(" \n\r"); - tokenizer > tok(ss.str(), sep); - vector args; - copy(tok.begin(), tok.end(), back_inserter(args)); - // Parse the file and store the options - store( boost::program_options::command_line_parser(args). - options(cmdline_options).positional(p).extra_parser(customSyntax).run(), vm); - } - - if (vm.count("version")) { - std::stringstream str; - str << mConfig["ExeName"] << " " << mConfig["ExeVersion"] - << " Revision: " << mConfig["BuildRevision"] << std::endl; - throw Base::ProgramInformation(str.str()); - } - - if (vm.count("console")) { - mConfig["Console"] = "1"; - mConfig["RunMode"] = "Cmd"; - } - - if (vm.count("module-path")) { - vector Mods = vm["module-path"].as< vector >(); - string temp; - for (vector::const_iterator It= Mods.begin();It != Mods.end();++It) - temp += *It + ";"; - temp.erase(temp.end()-1); - mConfig["AdditionalModulePaths"] = temp; - } - - if (vm.count("python-path")) { - vector Paths = vm["python-path"].as< vector >(); - for (vector::const_iterator It= Paths.begin();It != Paths.end();++It) - Base::Interpreter().addPythonPath(It->c_str()); - } - - if (vm.count("input-file")) { - vector files(vm["input-file"].as< vector >()); - int OpenFileCount=0; - for (vector::const_iterator It = files.begin();It != files.end();++It) { - - //cout << "Input files are: " - // << vm["input-file"].as< vector >() << "\n"; - - std::ostringstream temp; - temp << "OpenFile" << OpenFileCount; - mConfig[temp.str()] = *It; - OpenFileCount++; - } - std::ostringstream buffer; - buffer << OpenFileCount; - mConfig["OpenFileCount"] = buffer.str(); - } - - if (vm.count("output")) { - string file = vm["output"].as(); - mConfig["SaveFile"] = file; - } - - if (vm.count("hidden")) { - mConfig["StartHidden"] = "1"; - } - - if (vm.count("write-log")) { - mConfig["LoggingFile"] = "1"; - //mConfig["LoggingFileName"] = vm["write-log"].as(); - mConfig["LoggingFileName"] = mConfig["UserAppData"] + mConfig["ExeName"] + ".log"; - } - - if (vm.count("log-file")) { - mConfig["LoggingFile"] = "1"; - mConfig["LoggingFileName"] = vm["log-file"].as(); - } - - if (vm.count("user-cfg")) { - mConfig["UserParameter"] = vm["user-cfg"].as(); - } - - if (vm.count("system-cfg")) { - mConfig["SystemParameter"] = vm["system-cfg"].as(); - } - - if (vm.count("run-test")) { - string testCase = vm["run-test"].as(); - if ( "0" == testCase) { - testCase = "TestApp.All"; - } - mConfig["TestCase"] = testCase; - mConfig["RunMode"] = "Internal"; - mConfig["ScriptFileName"] = "FreeCADTest"; - //sScriptName = FreeCADTest; - } - - if (vm.count("single-instance")) { - mConfig["SingleInstance"] = "1"; - } - - if (vm.count("dump-config")) { - std::stringstream str; - for (std::map::iterator it=mConfig.begin(); it != mConfig.end(); ++it) { - str << it->first << "=" << it->second << std::endl; - } - throw Base::ProgramInformation(str.str()); - } - - if (vm.count("get-config")) { - std::string configKey = vm["get-config"].as(); - std::stringstream str; - std::map::iterator pos; - pos = mConfig.find(configKey); - if (pos != mConfig.end()) { - str << pos->second; - } - str << std::endl; - throw Base::ProgramInformation(str.str()); - } -} - void Application::ExtractUserPath() { // std paths diff --git a/src/App/Application.h b/src/App/Application.h index 2e7237ea9e..54872ecec7 100644 --- a/src/App/Application.h +++ b/src/App/Application.h @@ -555,8 +555,6 @@ private: static void logStatus(void); // the one and only pointer to the application object static Application *_pcSingleton; - /// argument helper function - static void ParseOptions(int argc, char ** argv); /// checks if the environment is alright //static void CheckEnv(void); /// Search for the FreeCAD home path based on argv[0]