/****************************************************************************/1// Eclipse SUMO, Simulation of Urban MObility; see https://eclipse.dev/sumo2// Copyright (C) 2001-2026 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 set option editable276*277* Tries to change the flag editable in the given option278*279* Throws an InvalidArgument if the option is not known280*281* @param[in] name The option's name282* @param[in] value editable value (true/false)283* @exception InvalidArgument If option doesn't exist284*/285void setOptionEditable(const std::string& name, const bool value);286287/// @}288289/// @name Methods for retrieving information about options290/// @{291292/** @brief Returns the information whether the named option is known293* @return true if an option has been added before under the given name, false otherwise294*/295bool exists(const std::string& name) const;296297/** @brief Returns the information whether the named option is set298*299* The named option is tried to be retrieved from the container. If300* it does not exist, an InvalidArgument is thrown. If it could be301* retrieved, the information whether the option has a value stored302* is returned.303*304* An option "is set" if a default value was supplied or a value has been305* set from the command line / the configuration file.306*307* @param[in] name The name of the option to check308* @param[in] failOnNonExistant Whether asking for an unregistered option should trigger an exception309* @return true if the option has a valid value, false otherwise310* @exception InvalidArgument If the named option is not known311*/312bool isSet(const std::string& name, bool failOnNonExistant = true) const;313314/** @brief Returns the information whether the named option has still the default value315*316* The named option is tried to be retrieved from the container. If317* it does not exist, an InvalidArgument is thrown. If it could be318* retrieved, the information whether the option still has the default319* value is returned.320*321* An option "is default" if no value has been set from the command line322* / the configuration file.323*324* @return true if the option still has the default value325* @exception InvalidArgument If the named option is not known326*/327bool isDefault(const std::string& name) const;328329/** @brief Returns the information whether the option is a boolean option330*331* The option is retrieved from the container, first, what may cause an InvalidArgument332* exception if it is not known. Otherwise, this option's isBool-method is called.333*334* @param[in] name The name of the option to check335* @return Whether the existing named option is a bool option336* @exception InvalidArgument If the option does not exist337*/338bool isBool(const std::string& name) const;339340/** @brief Checks whether the named option is usable as a file list (with at least a single file)341*342* The method returns true, if the named option is set with entries containing343* names of accessible files.344*345* Throw an InvalidArgument exception if the option is not known. If the option346* is not set, false is returned. Also, if the list is empty (contains delimiters only)347* or if one of the named files (obtained using getStringVector) does not exist,348* false is returned. Additionally, an error is sent to MsgHandler in both cases.349*350* In the case two delimiters were placed in the option value directly after351* each other, a warning is generated.352*353* @param[in] name The name of the option to check354* @return Whether the option contains names of files which can be accessed (for reading)355* @exception InvalidArgument If the option does not exist or is not a string-option356*/357bool isUsableFileList(const std::string& name) const;358359/** @brief Checks whether an option is set, which has options with a prefix depending on it.360*361* The method returns true, if the named option is set or no option depending on it is set.362* Throws an InvalidArgument exception if the option is not known.363*364* @param[in] name The name of the option to check365* @param[in] prefix The prefix of depending options366* @return Whether the dependencies are fulfilled367* @exception InvalidArgument If the option does not exist368*/369bool checkDependingSuboptions(const std::string& name, const std::string& prefix) const;370371/** @brief Modifies file name options according to the configuration path372*373* If the configuration path given is a relative one all filenames inside374* are adapted such that they refer to the correct location.375*376* @param[in] configuration The path to the configuration file377*/378void relocateFiles(const std::string& configuration) const;379380/** @brief Returns the synonymes of an option name381*382* The named option is extracted, first. An InvalidArgument is thrown if it383* does not exist. Otherwise, other names for the named option are searched384* and returned (the original name is not in the list).385* @param[in] name The name of the option to return synonymes of386* @return List of existing synonymes387* @exception InvalidArgument If the named option does not exist388**/389std::vector<std::string> getSynonymes(const std::string& name) const;390391/** @brief Returns the option description392*393* @param[in] name The name of the option to return the description of394* @return description395* @exception InvalidArgument If the named option does not exist396**/397const std::string& getDescription(const std::string& name) const;398399/** @brief Returns the option category400*401* @param[in] name The name of the option to return the category of402* @return category403* @exception InvalidArgument If the named option does not exist404**/405const std::string& getSubTopic(const std::string& name) const;406407/** @brief Returns the information whether the named option may be set408*409* An option is writable after initialisation, but as soon as it gets set,410* it is no longer writeable. This method returns whether the named option411* is writeable. If the named option is not known, an InvalidArgument412* is thrown.413*414* @param[in] name The name of the option to check415* @return Whether the value can be set416* @exception InvalidArgument If the option does not exist417*/418bool isWriteable(const std::string& name);419420/** @brief Returns the information whether the named option is editable421*422* @param[in] name The name of the option to check423* @return Whether the value is editable424* @exception InvalidArgument If the option does not exist425*/426bool isEditable(const std::string& name);427428/// @}429430/// @name Methods for retrieving values from options431/// @{432433/** @brief Returns the string-value of the named option (all options)434*435* This method returns the string-value of an existing option.436* If the named option does not exist, an437* InvalidArgument is thrown.438*439* @param[in] name The name of the option to return the string-value of440* @return The string-value of the named, existing option441* @exception InvalidArgument If the option does not exist442*/443std::string getValueString(const std::string& name) const;444445/** @brief Returns the string-value of the named option (only for Option_String)446*447* This method returns the string-value of an existing string-option.448* If the named option does not exist or is not a string-option, an449* InvalidArgument is thrown.450*451* @param[in] name The name of the option to return the string-value of452* @return The string-value of the named, existing string-option453* @exception InvalidArgument If the option does not exist or is not a string-option454*/455std::string getString(const std::string& name) const;456457/** @brief Returns the double-value of the named option (only for Option_Float)458*459* This method returns the double-value of an existing double-option.460* If the named option does not exist or is not a double-option, an461* InvalidArgument is thrown.462*463* @param[in] name The name of the option to return the double-value of464* @return The double-value of the named, existing double-option465* @exception InvalidArgument If the option does not exist or is not a double-option466*/467double getFloat(const std::string& name) const;468469/** @brief Returns the int-value of the named option (only for Option_Integer)470*471* This method returns the int-value of an existing int-option.472* If the named option does not exist or is not a int-option, an473* InvalidArgument is thrown.474*475* @param[in] name The name of the option to return the int-value of476* @return The int-value of the named, existing int-option477* @exception InvalidArgument If the option does not exist or is not a int-option478*/479int getInt(const std::string& name) const;480481/** @brief Returns the boolean-value of the named option (only for Option_Bool)482*483* This method returns the boolean-value of an existing boolean-option.484* If the named option does not exist or is not a boolean-option, an485* InvalidArgument is thrown.486*487* @param[in] name The name of the option to return the boolean-value of488* @return The boolean-value of the named, existing boolean-option489* @exception InvalidArgument If the option does not exist or is not a boolean-option490*/491bool getBool(const std::string& name) const;492493/** @brief Returns the list of integer-value of the named option (only for Option_IntVector)494*495* This method returns the int-vector-value of an existing int-vector-option.496* If the named option does not exist or is not a int-vector-option, an497* InvalidArgument is thrown.498*499* @param[in] name The name of the option to return the int-vector-value of500* @return The int-vector-value of the named, existing int-vector-option501* @exception InvalidArgument If the option does not exist or is not a int-vector-option502*/503const IntVector& getIntVector(const std::string& name) const;504505/** @brief Returns the list of string-value of the named option (only for Option_StringVector)506*507* This method returns the string-vector-value of an existing string-vector-option.508* If the named option does not exist or is not a string-vector-option, an509* InvalidArgument is thrown.510*511* If the legacy-divider ';' is found within the string, a warning is generated.512* The retrieved string is only splitted at ','.513*514* @param[in] name The name of the option to return the string-vector-value of515* @return The string-vector-value of the named, existing string-vector-option516* @exception InvalidArgument If the option does not exist or is not a string-vector-option517* @todo Is it possible to retrieve a const-reference of the string?518* @see getString()519*/520const StringVector& getStringVector(const std::string& name) const;521522/** @brief Returns the named option is a list of string values containing the specified item523*524* If the named option is not set, false is returned. Otherwise, the string-vector525* of this option is retrieved using getStringVector what may throw an526* InvalidArgument exception if the named option is not a string option or not527* existing at all.528*529* The given itemName is searched in the obtained string-vector and the530* method returns whether it is stored in the list or not.531*532* @param[in] optionName The name of the option to evaluate entries of533* @param[in] itemName The item to be searched for in the entries of the named option534* @return Whether the named item is set in the named string-option535* @exception InvalidArgument If the option does not exist or is not a string-option536* @see getStringVector()537* @todo Try to optimize - at each call, the vector is rebuilt538*/539bool isInStringVector(const std::string& optionName, const std::string& itemName) const;540541/// @}542543/// @name Methods for setting values into options544/// @{545546/** @brief Sets the given value for the named option547*548* The option is retrieved from the container, first, what yields in a InvalidArgument549* exception for not known options.550*551* If the option is not writable (was set before), an error is generated using552* reportDoubleSetting, and false is returned. Otherwise, the option is553* told to set the given value using Option::set. Possible problems herein554* are caught and reported to the error-handler, yielding in returning false.555*556* If the new value could be set, true is returned.557*558* @param[in] name The name of the option to set559* @param[in] value The value to set560* @return Whether the value could be set561* @exception InvalidArgument If the option does not exist562* @see reportDoubleSetting563* @see Option::set(const std::string &)564*/565bool set(const std::string& name, const std::string& value, const bool append = false);566567/** @brief Sets the given value for the named option as new default value568*569* The option is retrieved from the container, first, what yields in a InvalidArgument570* exception for not known options.571*572* If the option is not writable (was set before), an error is generated using573* reportDoubleSetting, and false is returned. Otherwise, the option is574* told to set the given value using Option::set. Possible problems herein575* are caught and reported to the error-handler, yielding in returning false.576*577* If the new value could be set, true is returned.578*579* @param[in] name The name of the option to set580* @param[in] value The value to set581* @return Whether the value could be set582* @exception InvalidArgument If the option does not exist583* @see reportDoubleSetting584* @see Option::set(const std::string &)585*/586bool setDefault(const std::string& name, const std::string& value);587588/** @brief Sets the given value for the option which can handle the given XML root589*590* The option is retrieved from the container, which yields in an InvalidArgument591* exception if no option is registered for the XML root. Then it uses the592* standard set method.593*594* @param[in] root The name of the XML root element to look for595* @param[in] value The value to set596* @return Whether the value could be set597* @exception InvalidArgument If the root element was not registered or the value could not be set598* @see OptionsCont::set(const std::string &, const std::string &)599*/600bool setByRootElement(const std::string& name, const std::string& value);601602/// @}603604/** @brief Resets all options to be writeable605*606* An option is writable after initialisation, but as soon as it gets set,607* it is no longer writeable. This method resets the writable-flag of all608* known options.609*/610void resetWritable();611612/// @brief Resets all options to default613void resetDefault();614615/// @brief Reset specific option to default616void resetDefault(const std::string& name);617618/** @brief Output operator619*620* Generates the output used when current option values shall be printed.621*622* @param[in] os The stream to write into623* @param[in] oc The options to print624* @return The stream to write into625*/626friend std::ostream& operator<<(std::ostream& os, const OptionsCont& oc);627628/// @brief Removes all information from the container629void clear();630631/** @brief Checks for help and configuration output, returns whether we should exit632*633* Returns false if no error was detected and the application may be executed634* (at least from this point of view). If missingOptions is true, the user is635* informed that they should be supplied (returns true). Otherwise it is checked636* whether help shall be printed what is done if so, returning true. Also, it637* is checked whether the set options shall be printed and the configuration638* template or the current configuration shall be written.639*640* This method throws a ProcessError if the configuration should be saved,641* but the file is not accessible. An error message is supplied.642*643* @param[in] missingOptions Whether no options have been given644* @return Whether the application shall stop645* @exception ProcessError If the configuration file could not be saved646*/647bool processMetaOptions(bool missingOptions);648649void localizeDescriptions();650651/// @brief return the list of subtopics652const std::vector<std::string>& getSubTopics() const;653654/// @brief return the list of entries for the given subtopic655std::vector<std::string> getSubTopicsEntries(const std::string& subtopic) const;656657/// @brief return the type name for the given option658std::string getTypeName(const std::string name);659660/// @brief get options full name661const std::string& getFullName() const;662663/// @brief check if options container is empty664bool isEmpty() const;665666/// @brief get begin addresses iterator667std::vector<std::pair<std::string, Option*> >::const_iterator begin() const;668669/// @brief get begin addresses iterator670std::vector<std::pair<std::string, Option*> >::const_iterator end() const;671672/// @brief make a copy of this OptionsCont instance673OptionsCont* clone() const;674675private:676/** @brief Returns the named option677*678* If the named option does not exist, an InvalidArgument is thrown.679*680* @param[in] name The name of the option to return681* @return The named option682*/683Option* getSecure(const std::string& name) const;684685/** @brief Reports an error that the option has already been set686*687* Using the given option name, an error string is generated and reported to688* MsgHandler-error instance.689*690* @param[in] name The name of the option that was already set691*/692void reportDoubleSetting(const std::string& arg) const;693694/** @brief Converts an abbreviation into a name695*696* Build and returns the string which consists of the given character only.697*698* @param[in] abbr The abbreviation to convert into a string699* @return The abbreviation converted into a string700*/701std::string convertChar(char abbr) const;702703/** @brief Writes the given string 'formatted'704*705* The given string is split so that no word-wrapping occurs at line ends.706* The text is wrapped at ';' or ' '.707*708* @param[in] os The stream to write the text into709* @param[in] what The text to write710* @param[in] offset ?711* @param[in] nextOffset ?712* @todo Describe parameter713*/714void splitLines(std::ostream& os, std::string what, int offset, int nextOffset);715716/// @brief Whether the descriptino has already been translated to the locale language717bool myAmLocalized = false;718719/// @brief The static options container used720static OptionsCont myOptions;721722/// @brief option-addresses723std::vector<std::pair<std::string, Option*> > myAddresses;724725/// @brief option maps sorted by name (for addresses AND their synonyms)726std::map<std::string, Option*> myValues;727728/// @brief some information on the application729std::string myAppName, myFullName, myAppDescription, myAdditionalMessage;730731/// @brief list of call examples732std::vector< std::pair<std::string, std::string> > myCallExamples;733734/// @brief lists of option subtopics and copyright notices735std::vector<std::string> mySubTopics, myCopyrightNotices;736737/// @brief A map from subtopic to option738std::map<std::string, std::vector<std::string> > mySubTopicEntries;739740/// @brief A map from XML root element to option741std::map<std::string, std::string> myXMLDefaults;742743/// @brief A map from deprecated options to a bool indicating whether we warned about deprecation744mutable std::map<std::string, bool> myDeprecatedSynonymes;745746/// @brief default copy constructor, but private747OptionsCont(const OptionsCont& s) = default;748749/// @brief invalid assignment operator750OptionsCont& operator=(const OptionsCont& s) = delete;751};752753754