/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2025 German Aerospace Center (DLR) and others.3// This program and the accompanying materials are made available under the4// terms of the Eclipse Public License 2.0 which is available at5// https://www.eclipse.org/legal/epl-2.0/6// This Source Code may also be made available under the following Secondary7// Licenses when the conditions for such availability set forth in the Eclipse8// Public License 2.0 are satisfied: GNU General Public License, version 29// or later which is available at10// https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html11// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-or-later12/****************************************************************************/13/// @file OptionsCont.h14/// @author Daniel Krajzewicz15/// @author Jakob Erdmann16/// @author Michael Behrisch17/// @author Walter Bamberger18/// @date Mon, 17 Dec 200119///20// A storage for options (typed value containers)21/****************************************************************************/22#pragma once23#include <config.h>2425#include <map>26#include <string>27#include <vector>28#include <iostream>29#include "Option.h"303132// ===========================================================================33// class definitions34// ===========================================================================35/**36* @class OptionsCont37* @brief A storage for options typed value containers)38*39* This container stores options (typed value containers) by their names.40* In the case of command line tools, this container is the main interface41* between a user's definitions about what to do (command line options,42* configuration files) and the application.43*44* At the begin, the application should initialise the container. Because45* the OptionsCont is also responsible for printing the help screen, one46* should name and describe the application, first. This means that the47* first usage of this container should look similar to this:48* @code49* OptionsCont &oc = OptionsCont::getOptions();50* // give some application descriptions51* oc.setApplicationDescription(<ONE_LINE_DESCRIPTION>);52* oc.setApplicationName(<APPLICATION_NAME>, "SUMO <APPLICATION_NAME> Version " + (string)VERSION_STRING);53* @endcode54* @see setApplicationDescription55* @see setApplicationName56*57* Then, you may also add some example calls using addCallExample.58* @see addCallExample59*60* In the next step, option subtopics are registered. This is needed61* for the help screen and for writing the templates/saving configurations.62* A subtopic is added using addOptionSubTopic(<SUBTOPIC_NAME>).63* @see addOptionSubTopic64*65* After this, you may add options to the container. This is done using66* doRegister. This method requires a long name for the option and67* the value container. The value container must be an instance of68* one of the classes derived from "Option". Do not use Option itself!69* This is a base class which is meant to supply a default behaviour,70* but this default behaviour throws exceptions only!71* @see Option72* @see doRegister73* @see addSynonyme74*75* Once stored inside this container, options will not be visible to the76* world and are deleted by the container. Only values and stati of the77* options may be returned. While accessing the options, the programmer78* must assure that he asks for the right value (only Option_Bool is able79* to return a boolean value, other option types will throw exceptions).80* Further, options added to the container must not be deleted outside81* this container (the container becomes the owner).82*83* For being printed in the help screen, a description together with the84* subtopic the option belongs to must be given to OptionsCont. This is85* done using addDescription(<OPTION_NAME>, <SUBTOPIC>, <DESCRIPTION>).86* @see addDescription87*/88class OptionsCont {8990public:91/// @brief Retrieves the options92static OptionsCont& getOptions();9394/// @brief empty option container95static OptionsCont EMPTY_OPTIONS;9697/// @brief Constructor98OptionsCont();99100/// @brief Destructor101~OptionsCont();102103/// @name Methods setting and getting information about the appplication and currently set options104/// @{105106/** @brief Sets the application name107*108* @param[in] name The name of the excutable109* @param[in] v The name of the executable with version information110*/111void setApplicationName(const std::string& appName, const std::string& fullName);112113/** @brief Sets the application description114*115* @param[in] appDesc A description of the application116*/117void setApplicationDescription(const std::string& appDesc);118119/** @brief Add a call example120*121* @param[in] example A call example (without the app name)122* @param[in] desc A verbose description123*/124void addCallExample(const std::string& example, const std::string& desc);125126/** @brief Sets an additional message to be printed at the begin of the help screen127*128* @param[in] example Some additional information about how to use the application129*/130void setAdditionalHelpMessage(const std::string& add);131132/** @brief Adds a copyright notice to the help output133*134* @param[in] copyrightLine The line to put out as a copyright notice135*/136void addCopyrightNotice(const std::string& copyrightLine);137138/** @brief Removes all copyright information139*/140void clearCopyrightNotices();141142/** @brief Adds an option subtopic143*144* Sub-topics are used to join several options into one thematic field.145* They are used on writing the help screen and the configuration. They have146* no further meaning besides making the outputs better readable.147*148* @param[in] topic The options sub topic149*/150void addOptionSubTopic(const std::string& topic);151152/** @brief Prints the help153*154* @param[in] os The stream to write the help into155*/156void printHelp(std::ostream& os);157158/** @brief Prints help on the given topic159*160* @param[in] topic The topic name161* @param[in] os The stream to write the help into162*/163void printHelpOnTopic(const std::string& topic, int tooLarge, int maxSize, std::ostream& os);164165/** @brief Writes the configuration166*167* The configuration is written as XML into the given stream, allowing168* to reload it on a next run.169*170* @param[in] os The stream to write the configuration into171* @param[in] filled Whether only set (and not default) options shall be written172* @param[in] complete Whether all options shall be written173* @param[in] addComments Whether comments (option descriptions) shall be written174* @param[in] inComment Whether -- in input shall be converted to -- (semantically equivalent but allowed in XML comments)175*/176void writeConfiguration(std::ostream& os, const bool filled,177const bool complete, const bool addComments, const std::string& relativeTo = "",178const bool forceRelative = false, const bool inComment = false, const std::string& indent = "") const;179180/** @brief Writes the xml schema for the configuration181*182* The schema for the configuration is written as XML into the given stream,183* allowing to validate the configuration against.184*185* @param[in] os The stream to write the schema into186*/187void writeSchema(std::ostream& os);188189/** @brief Writes a standard XML header, including the configuration190*191* The header consists of the xml-declaration with encoding as defined192* by SUMOSAXAttributes::ENCODING, followed by a note which contains193* the current date and time and the application configuration (set values).194*195* @param[in] os The stream to write the header into196*/197void writeXMLHeader(std::ostream& os, const bool includeConfig = true) const;198199/// @}200201/// @name Methods for registering options202/// @{203204/** @brief Adds an option under the given name205* @param[in] name The (long) name of the option206* @param[in] o The option (typed value storage)207* @exception InvalidArgument If the name is already used208*/209void doRegister(const std::string& name, Option* o);210211/** @brief Adds an option under the given name and the given abbreviation212*213* Adds the option under both names using void doRegister(const std::string &name, Option *v);214*215* @param[in] name The (long) name of the option216* @param[in] abbr The (short) name of the option217* @param[in] v The option (typed value storage)218* @exception InvalidArgument If one of the names is already used219*/220void doRegister(const std::string& name, char abbr, Option* o);221222/** @brief Adds a synonyme for an options name (any order)223*224* Tries to find one of the synonymes. If both are known and the option differs225* for both, an InvalidArgument exception is thrown. If none is known, also.226*227* If one of the synonymes is known and the other not, the option from the known228* one is made accessible by the other.229*230* In the case both synonymes are known and have the same option assigned, nothing231* is done.232*233* @param[in] name1 The first synonyme234* @param[in] name2 The second synonyme235* @param[in] isDeprecated whether the synonyme is considered deprecated236* @exception InvalidArgument If none of the synonymes or both synonymes with different options were registered before237*/238void addSynonyme(const std::string& name1, const std::string& name2, bool isDeprecated = false);239240/** @brief Adds an XML root element to handle by default. The special root "" denotes the default handler.241*242* @param[in] name The option name243* @param[in] xmlRoot The name of the xml root element to handle244*/245void addXMLDefault(const std::string& name, const std::string& xmlRoot = "");246247/** @brief Adds a description for an option248*249* Tries to retrieve the named option and to set the given description. Adds250* the name to the list of option names to be located in the named subtopic.251*252* Throws an InvalidArgument if the option is not known or already has253* a description set.254*255* @param[in] name The option's name256* @param[in] subtopic The subtopic to locate the description within257* @param[in] description The description258* @exception InvalidArgument If none of the synonymes or both synonymes with different options were registered before259*/260void addDescription(const std::string& name, const std::string& subtopic, const std::string& description);261262/** @brief mark option as required263*264* Tries to retrieve the named option and set as required. Adds265* the name to the list of option names to be located in the named subtopic.266*267* Throws an InvalidArgument if the option is not known268*269* @param[in] name The option's name270* @param[in] subtopic The subtopic to locate the description within271* @exception InvalidArgument If none of the synonymes or both synonymes with different options were registered before272*/273void setFurtherAttributes(const std::string& name, const std::string& subtopic, bool required, bool positional, const std::string& listSep);274275/** @brief Adds a category for an option276*277* Tries to retrieve the named option and to set the given category. Adds278* the name to the list of option names to be located in the named subtopic.279*280* Throws an InvalidArgument if the option is not known or already has281* a category set.282*283* @param[in] name The option's name284* @param[in] subtopic The subtopic to locate the category within285* @param[in] category The category286* @exception InvalidArgument If none of the synonymes or both synonymes with different options were registered before287*/288void addCategory(const std::string& name, const std::string& subtopic, const std::string& category);289290/// @}291292/// @name Methods for retrieving information about options293/// @{294295/** @brief Returns the information whether the named option is known296* @return true if an option has been added before under the given name, false otherwise297*/298bool exists(const std::string& name) const;299300/** @brief Returns the information whether the named option is set301*302* The named option is tried to be retrieved from the container. If303* it does not exist, an InvalidArgument is thrown. If it could be304* retrieved, the information whether the option has a value stored305* is returned.306*307* An option "is set" if a default value was supplied or a value has been308* set from the command line / the configuration file.309*310* @param[in] name The name of the option to check311* @param[in] failOnNonExistant Whether asking for an unregistered option should trigger an exception312* @return true if the option has a valid value, false otherwise313* @exception InvalidArgument If the named option is not known314*/315bool isSet(const std::string& name, bool failOnNonExistant = true) const;316317/** @brief Returns the information whether the named option has still the default value318*319* The named option is tried to be retrieved from the container. If320* it does not exist, an InvalidArgument is thrown. If it could be321* retrieved, the information whether the option still has the default322* value is returned.323*324* An option "is default" if no value has been set from the command line325* / the configuration file.326*327* @return true if the option still has the default value328* @exception InvalidArgument If the named option is not known329*/330bool isDefault(const std::string& name) const;331332/** @brief Returns the information whether the option is a boolean option333*334* The option is retrieved from the container, first, what may cause an InvalidArgument335* exception if it is not known. Otherwise, this option's isBool-method is called.336*337* @param[in] name The name of the option to check338* @return Whether the existing named option is a bool option339* @exception InvalidArgument If the option does not exist340*/341bool isBool(const std::string& name) const;342343/** @brief Checks whether the named option is usable as a file list (with at least a single file)344*345* The method returns true, if the named option is set with entries containing346* names of accessible files.347*348* Throw an InvalidArgument exception if the option is not known. If the option349* is not set, false is returned. Also, if the list is empty (contains delimiters only)350* or if one of the named files (obtained using getStringVector) does not exist,351* false is returned. Additionally, an error is sent to MsgHandler in both cases.352*353* In the case two delimiters were placed in the option value directly after354* each other, a warning is generated.355*356* @param[in] name The name of the option to check357* @return Whether the option contains names of files which can be accessed (for reading)358* @exception InvalidArgument If the option does not exist or is not a string-option359*/360bool isUsableFileList(const std::string& name) const;361362/** @brief Checks whether an option is set, which has options with a prefix depending on it.363*364* The method returns true, if the named option is set or no option depending on it is set.365* Throws an InvalidArgument exception if the option is not known.366*367* @param[in] name The name of the option to check368* @param[in] prefix The prefix of depending options369* @return Whether the dependencies are fulfilled370* @exception InvalidArgument If the option does not exist371*/372bool checkDependingSuboptions(const std::string& name, const std::string& prefix) const;373374/** @brief Modifies file name options according to the configuration path375*376* If the configuration path given is a relative one all filenames inside377* are adapted such that they refer to the correct location.378*379* @param[in] configuration The path to the configuration file380*/381void relocateFiles(const std::string& configuration) const;382383/** @brief Returns the synonymes of an option name384*385* The named option is extracted, first. An InvalidArgument is thrown if it386* does not exist. Otherwise, other names for the named option are searched387* and returned (the original name is not in the list).388* @param[in] name The name of the option to return synonymes of389* @return List of existing synonymes390* @exception InvalidArgument If the named option does not exist391**/392std::vector<std::string> getSynonymes(const std::string& name) const;393394/** @brief Returns the option description395*396* @param[in] name The name of the option to return the description of397* @return description398* @exception InvalidArgument If the named option does not exist399**/400const std::string& getDescription(const std::string& name) const;401402/** @brief Returns the option category403*404* @param[in] name The name of the option to return the category of405* @return category406* @exception InvalidArgument If the named option does not exist407**/408const std::string& getSubTopic(const std::string& name) const;409410/** @brief Returns the information whether the named option may be set411*412* An option is writable after initialisation, but as soon as it gets set,413* it is no longer writeable. This method returns whether the named option414* is writeable. If the named option is not known, an InvalidArgument415* is thrown.416*417* @param[in] name The name of the option to check418* @return Whether the value can be set419* @exception InvalidArgument If the option does not exist420*/421bool isWriteable(const std::string& name);422423/// @}424425/// @name Methods for retrieving values from options426/// @{427428/** @brief Returns the string-value of the named option (all options)429*430* This method returns the string-value of an existing option.431* If the named option does not exist, an432* InvalidArgument is thrown.433*434* @param[in] name The name of the option to return the string-value of435* @return The string-value of the named, existing option436* @exception InvalidArgument If the option does not exist437*/438std::string getValueString(const std::string& name) const;439440/** @brief Returns the string-value of the named option (only for Option_String)441*442* This method returns the string-value of an existing string-option.443* If the named option does not exist or is not a string-option, an444* InvalidArgument is thrown.445*446* @param[in] name The name of the option to return the string-value of447* @return The string-value of the named, existing string-option448* @exception InvalidArgument If the option does not exist or is not a string-option449*/450std::string getString(const std::string& name) const;451452/** @brief Returns the double-value of the named option (only for Option_Float)453*454* This method returns the double-value of an existing double-option.455* If the named option does not exist or is not a double-option, an456* InvalidArgument is thrown.457*458* @param[in] name The name of the option to return the double-value of459* @return The double-value of the named, existing double-option460* @exception InvalidArgument If the option does not exist or is not a double-option461*/462double getFloat(const std::string& name) const;463464/** @brief Returns the int-value of the named option (only for Option_Integer)465*466* This method returns the int-value of an existing int-option.467* If the named option does not exist or is not a int-option, an468* InvalidArgument is thrown.469*470* @param[in] name The name of the option to return the int-value of471* @return The int-value of the named, existing int-option472* @exception InvalidArgument If the option does not exist or is not a int-option473*/474int getInt(const std::string& name) const;475476/** @brief Returns the boolean-value of the named option (only for Option_Bool)477*478* This method returns the boolean-value of an existing boolean-option.479* If the named option does not exist or is not a boolean-option, an480* InvalidArgument is thrown.481*482* @param[in] name The name of the option to return the boolean-value of483* @return The boolean-value of the named, existing boolean-option484* @exception InvalidArgument If the option does not exist or is not a boolean-option485*/486bool getBool(const std::string& name) const;487488/** @brief Returns the list of integer-value of the named option (only for Option_IntVector)489*490* This method returns the int-vector-value of an existing int-vector-option.491* If the named option does not exist or is not a int-vector-option, an492* InvalidArgument is thrown.493*494* @param[in] name The name of the option to return the int-vector-value of495* @return The int-vector-value of the named, existing int-vector-option496* @exception InvalidArgument If the option does not exist or is not a int-vector-option497*/498const IntVector& getIntVector(const std::string& name) const;499500/** @brief Returns the list of string-value of the named option (only for Option_StringVector)501*502* This method returns the string-vector-value of an existing string-vector-option.503* If the named option does not exist or is not a string-vector-option, an504* InvalidArgument is thrown.505*506* If the legacy-divider ';' is found within the string, a warning is generated.507* The retrieved string is only splitted at ','.508*509* @param[in] name The name of the option to return the string-vector-value of510* @return The string-vector-value of the named, existing string-vector-option511* @exception InvalidArgument If the option does not exist or is not a string-vector-option512* @todo Is it possible to retrieve a const-reference of the string?513* @see getString()514*/515const StringVector& getStringVector(const std::string& name) const;516517/** @brief Returns the named option is a list of string values containing the specified item518*519* If the named option is not set, false is returned. Otherwise, the string-vector520* of this option is retrieved using getStringVector what may throw an521* InvalidArgument exception if the named option is not a string option or not522* existing at all.523*524* The given itemName is searched in the obtained string-vector and the525* method returns whether it is stored in the list or not.526*527* @param[in] optionName The name of the option to evaluate entries of528* @param[in] itemName The item to be searched for in the entries of the named option529* @return Whether the named item is set in the named string-option530* @exception InvalidArgument If the option does not exist or is not a string-option531* @see getStringVector()532* @todo Try to optimize - at each call, the vector is rebuilt533*/534bool isInStringVector(const std::string& optionName, const std::string& itemName) const;535536/// @}537538/// @name Methods for setting values into options539/// @{540541/** @brief Sets the given value for the named option542*543* The option is retrieved from the container, first, what yields in a InvalidArgument544* exception for not known options.545*546* If the option is not writable (was set before), an error is generated using547* reportDoubleSetting, and false is returned. Otherwise, the option is548* told to set the given value using Option::set. Possible problems herein549* are caught and reported to the error-handler, yielding in returning false.550*551* If the new value could be set, true is returned.552*553* @param[in] name The name of the option to set554* @param[in] value The value to set555* @return Whether the value could be set556* @exception InvalidArgument If the option does not exist557* @see reportDoubleSetting558* @see Option::set(const std::string &)559*/560bool set(const std::string& name, const std::string& value, const bool append = false);561562/** @brief Sets the given value for the named option as new default value563*564* The option is retrieved from the container, first, what yields in a InvalidArgument565* exception for not known options.566*567* If the option is not writable (was set before), an error is generated using568* reportDoubleSetting, and false is returned. Otherwise, the option is569* told to set the given value using Option::set. Possible problems herein570* are caught and reported to the error-handler, yielding in returning false.571*572* If the new value could be set, true is returned.573*574* @param[in] name The name of the option to set575* @param[in] value The value to set576* @return Whether the value could be set577* @exception InvalidArgument If the option does not exist578* @see reportDoubleSetting579* @see Option::set(const std::string &)580*/581bool setDefault(const std::string& name, const std::string& value);582583/** @brief Sets the given value for the option which can handle the given XML root584*585* The option is retrieved from the container, which yields in an InvalidArgument586* exception if no option is registered for the XML root. Then it uses the587* standard set method.588*589* @param[in] root The name of the XML root element to look for590* @param[in] value The value to set591* @return Whether the value could be set592* @exception InvalidArgument If the root element was not registered or the value could not be set593* @see OptionsCont::set(const std::string &, const std::string &)594*/595bool setByRootElement(const std::string& name, const std::string& value);596597/// @}598599/** @brief Resets all options to be writeable600*601* An option is writable after initialisation, but as soon as it gets set,602* it is no longer writeable. This method resets the writable-flag of all603* known options.604*/605void resetWritable();606607/// @brief Resets all options to default608void resetDefault();609610/// @brief Reset specific option to default611void resetDefault(const std::string& name);612613/** @brief Output operator614*615* Generates the output used when current option values shall be printed.616*617* @param[in] os The stream to write into618* @param[in] oc The options to print619* @return The stream to write into620*/621friend std::ostream& operator<<(std::ostream& os, const OptionsCont& oc);622623/// @brief Removes all information from the container624void clear();625626/** @brief Checks for help and configuration output, returns whether we should exit627*628* Returns false if no error was detected and the application may be executed629* (at least from this point of view). If missingOptions is true, the user is630* informed that they should be supplied (returns true). Otherwise it is checked631* whether help shall be printed what is done if so, returning true. Also, it632* is checked whether the set options shall be printed and the configuration633* template or the current configuration shall be written.634*635* This method throws a ProcessError if the configuration should be saved,636* but the file is not accessible. An error message is supplied.637*638* @param[in] missingOptions Whether no options have been given639* @return Whether the application shall stop640* @exception ProcessError If the configuration file could not be saved641*/642bool processMetaOptions(bool missingOptions);643644/// @brief return the list of subtopics645const std::vector<std::string>& getSubTopics() const;646647/// @brief return the list of entries for the given subtopic648std::vector<std::string> getSubTopicsEntries(const std::string& subtopic) const;649650/// @brief return the type name for the given option651std::string getTypeName(const std::string name);652653/// @brief get options full name654const std::string& getFullName() const;655656/// @brief check if options container is empty657bool isEmpty() const;658659/// @brief get begin addresses iterator660std::vector<std::pair<std::string, Option*> >::const_iterator begin() const;661662/// @brief get begin addresses iterator663std::vector<std::pair<std::string, Option*> >::const_iterator end() const;664665/// @brief make a copy of this OptionsCont instance666OptionsCont* clone() const;667668private:669/** @brief Returns the named option670*671* If the named option does not exist, an InvalidArgument is thrown.672*673* @param[in] name The name of the option to return674* @return The named option675*/676Option* getSecure(const std::string& name) const;677678/** @brief Reports an error that the option has already been set679*680* Using the given option name, an error string is generated and reported to681* MsgHandler-error instance.682*683* @param[in] name The name of the option that was already set684*/685void reportDoubleSetting(const std::string& arg) const;686687/** @brief Converts an abbreviation into a name688*689* Build and returns the string which consists of the given character only.690*691* @param[in] abbr The abbreviation to convert into a string692* @return The abbreviation converted into a string693*/694std::string convertChar(char abbr) const;695696/** @brief Writes the given string 'formatted'697*698* The given string is split so that no word-wrapping occurs at line ends.699* The text is wrapped at ';' or ' '.700*701* @param[in] os The stream to write the text into702* @param[in] what The text to write703* @param[in] offset ?704* @param[in] nextOffset ?705* @todo Describe parameter706*/707void splitLines(std::ostream& os, std::string what, int offset, int nextOffset);708709/// @brief The static options container used710static OptionsCont myOptions;711712/// @brief option-addresses713std::vector<std::pair<std::string, Option*> > myAddresses;714715/// @brief option maps sorted by name (for addresses AND their synonyms)716std::map<std::string, Option*> myValues;717718/// @brief some information on the application719std::string myAppName, myFullName, myAppDescription, myAdditionalMessage;720721/// @brief list of call examples722std::vector< std::pair<std::string, std::string> > myCallExamples;723724/// @brief lists of option subtopics and copyright notices725std::vector<std::string> mySubTopics, myCopyrightNotices;726727/// @brief A map from subtopic to option728std::map<std::string, std::vector<std::string> > mySubTopicEntries;729730/// @brief A map from XML root element to option731std::map<std::string, std::string> myXMLDefaults;732733/// @brief A map from deprecated options to a bool indicating whether we warned about deprecation734mutable std::map<std::string, bool> myDeprecatedSynonymes;735736/// @brief default copy constructor, but private737OptionsCont(const OptionsCont& s) = default;738739/// @brief invalid assignment operator740OptionsCont& operator=(const OptionsCont& s) = delete;741};742743744