Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

Ignore:
Timestamp:
Aug 21, 2008, 9:23:11 PM (16 years ago)
Author:
rgrieder
Message:
  • Finished CommandLineArgument completely. You can also use SetCommandLineSwitch to define boolean switches.
  • Added StaticConversion to Covert.h (compile time type conversion checking)
  • Fixed a bug in Exception
  • Added getAllStrings() to SubString
File:
1 edited

Legend:

Unmodified
Added
Removed
  • code/branches/gui/src/core/CommandLine.h

    r1663 r1664  
    3636#include "Exception.h"
    3737
    38 
    3938#define SetCommandLineArgument(name, defaultValue) \
    4039    BaseCommandLineArgument& CmdArgumentDummyBoolVar##name \
    4140    = orxonox::CommandLine::addCommandLineArgument(#name, defaultValue)
     41#define SetCommandLineSwitch(name) \
     42    BaseCommandLineArgument& CmdArgumentDummyBoolVar##name \
     43    = orxonox::CommandLine::addCommandLineArgument(#name, false)
     44
    4245
    4346namespace orxonox
    4447{
     48    /**
     49    @brief
     50        Template struct which creates a distinct type for every integer constant.
     51    @note
     52        This allows to select a different function depending on a boolean value
     53        when creating a new CommandLineArgument.
     54        From 'Modern C++ Design' (Alexandrescu 2001).
     55    */
     56    template <int v>
     57    struct Int2Type
     58    {
     59        enum { value = v };
     60    };
     61
     62    /**
     63    @brief
     64        Base class for CommandLineArguments.
     65    */
    4566    class _CoreExport BaseCommandLineArgument
    4667    {
     
    4869
    4970    public:
     71        //! Tells whether the value has been changed by the command line.
    5072        bool hasDefaultValue() const { return bHasDefaultValue_; }
     73        //! Returns the name of the argument.
    5174        const std::string& getName() const { return name_; }
     75
     76        //! Returns the shortcut (example: "-p 22" for "--port 22") of the argument.
     77        //! Evaluates to "" if none there is none.
    5278        const std::string& getShortcut() const { return shortcut_; }
     79        //! Sets the shortcut for the argument
    5380        BaseCommandLineArgument& setShortcut(const std::string& shortcut)
    5481        { this->shortcut_ = shortcut; return *this; }
     82
     83        //! Returns the usage information
     84        const std::string& getInformation() const { return this->usageInformation_; }
     85        //! Sets the option information when displaying orxonox usage.
     86        BaseCommandLineArgument& setInformation(const std::string& usage)
     87        { this->usageInformation_ = usage; return *this; }
    5588
    5689    protected:
     
    6093        { }
    6194
     95        //! Undefined copy constructor
    6296        BaseCommandLineArgument(const BaseCommandLineArgument& instance);
    6397        virtual ~BaseCommandLineArgument() { }
    6498
     99        //! Parses the value string of a command line argument.
    65100        virtual void parse(const std::string& value) = 0;
    66101
     102        //! Tells whether the value has been changed by the command line.
    67103        bool bHasDefaultValue_;
    68104
    69105    private:
    70         std::string name_;
    71         std::string shortcut_;
     106        std::string name_;             //!< Name of the argument
     107        std::string shortcut_;         //!< Shortcut of the argument. @see getShortcut().
     108        std::string usageInformation_; //!< Tells about the usage of this parameter
    72109    };
    73110
    74111
     112    /**
     113    @brief
     114        Container class for a command line argument of type T.
     115       
     116        Whenever you want to have an option specified by a command line switch,
     117        you need to first define it with SetCommandLineArgument(name, defaultValue).
     118        It is then added to a map and possibly changed when the command line is being parsed.
     119        If the option was not given, you can detect this by asking hasDefaultValue().
     120       
     121        There is a possibility to define a short cut so you can write "-p 20" instead of "--port 20".
     122        Note the difference between "-" and "--"!
     123        Also, there is no restriction to the number of strings you add after --name.
     124        So "--startVector (2, 4, 5)" is perfectly legal.
     125
     126        Retrieving an argument is possible with the getCommandLineArgument function of the
     127        CommandLine class. It is a Singleton, but the public interface is static.
     128    */
    75129    template <class T>
    76130    class CommandLineArgument : public BaseCommandLineArgument
    77131    {
     132        // Only let CommandLine change the value.
    78133        friend class CommandLine;
    79134
    80135    public:
     136        //! Returns the actual value of the argument. Can be equal to default value.
    81137        T getValue() const { return value_; }
     138        //! Returns the given default value as type T.
    82139        T getDefaultValue() const { return defaultValue_; }
    83140
    84141    private:
     142        //! Constructor initialises both value_ and defaultValue_ with defaultValue.
    85143        CommandLineArgument(const std::string& name, const T& defaultValue)
    86144            : BaseCommandLineArgument(name)
     
    91149        virtual void parse(const std::string& value);
    92150
    93         T value_;
    94         T defaultValue_;
     151        T value_;            //!< The actual value
     152        T defaultValue_;     //!< Default value. Should not be changed.
    95153    };
    96154
     155    /**
     156    @brief
     157        Parses a value string for a command line argument.
     158        It simply uses convertValue(Output, Input) to do that.
     159    */
    97160    template <class T>
    98161    void CommandLineArgument<T>::parse(const std::string& value)
     
    108171    }
    109172
    110 
     173    /**
     174    @brief
     175        Parses a value string for a command line argument.
     176        It simply uses convertValue(Output, Input) to do that.
     177        This is a template specialisation for bool type. That is necessary
     178        so that you can have simple command line switches.
     179    */
     180    template <>
     181    inline void CommandLineArgument<bool>::parse(const std::string& value)
     182    {
     183        if (convertValue(&this->value_, value))
     184        {
     185            this->bHasDefaultValue_ = false;
     186        }
     187        else if (value == "")
     188        {
     189            this->bHasDefaultValue_ = false;
     190            this->value_ = true;
     191        }
     192        else
     193        {
     194            ThrowException(Argument, "Could not read command line argument '" + getName() + "'.");
     195        }
     196    }
     197
     198
     199    /**
     200    @brief
     201        Global interface to command line options.
     202        Allows to add and retrieve command line arguments. Also does the parsing.
     203    @note
     204        Internally it is a Singleton, but the public interface is static.
     205    @see
     206        CommandLineArgument
     207    */
    111208    class _CoreExport CommandLine
    112209    {
    113210    public:
    114211
    115         static void parse(int argc, char** argv) { _getInstance()._parse(argc, argv); }
     212        //! Parse redirection to internal member method.
     213        static void parse(const std::vector<std::string>& arguments) { _getInstance()._parse(arguments); }
     214
     215        static std::string getUsageInformation();
    116216
    117217        template <class T>
    118218        static const CommandLineArgument<T>* getCommandLineArgument(const std::string& name);
    119         template <class T>
    120         static BaseCommandLineArgument& addCommandLineArgument(const std::string& name,
    121             const T& defaultValue);
     219        //! Writes the argument value in the given parameter.
     220        template <class T>
     221        static void getCommandLineValue(const std::string& name, T* value)
     222        { *value = getCommandLineArgument<T>(name)->getValue(); }
     223        template <class T>
     224        static BaseCommandLineArgument& addCommandLineArgument(const std::string& name, T defaultValue);
    122225
    123226    private:
     227        //! Constructor initialises bFirstTimeParse_ with true.
    124228        CommandLine() : bFirstTimeParse_(true) { }
     229        //! Undefined copy constructor
    125230        CommandLine(const CommandLine& instance);
    126231        ~CommandLine();
     
    128233        static CommandLine& _getInstance();
    129234
    130         void _parse(int argc, char** argv);
     235        void _parse(const std::vector<std::string>& arguments);
    131236        void checkFullArgument(const std::string& name, const std::string& value);
    132237        void checkShortcut(const std::string& shortcut, const std::string& value);
    133238
     239        template <class T>
     240        BaseCommandLineArgument* createArg(const std::string& name, T defaultValue, Int2Type<0> isString);
     241        template <class T>
     242        BaseCommandLineArgument* createArg(const std::string& name, T defaultValue, Int2Type<1> isString);
     243
     244        /**
     245            Tells whether we parse the first expression. The CommmandLineArguments are added before main().
     246            So when we call parse() the first time, we need to create a map with all shortcuts since these
     247            get added after addCommandLineArgument().
     248        */
    134249        bool bFirstTimeParse_;
    135250
     251        //! Holds all pointers to the arguments and serves as a search map by name.
    136252        std::map<std::string, BaseCommandLineArgument*> cmdLineArgs_;
     253        //! Search map by chortcut for the arguments.
    137254        std::map<std::string, BaseCommandLineArgument*> cmdLineArgsShortcut_;
    138255    };
    139256
    140257
     258    /**
     259    @brief
     260        Retrieves a CommandLineArgument.
     261        The method throws an exception if 'name' was not found or the value could not be converted.
     262    @note
     263        You shold of course not call this method before the command line has been parsed.
     264    */
    141265    template <class T>
    142266    const CommandLineArgument<T>* CommandLine::getCommandLineArgument(const std::string& name)
     
    162286    }
    163287
    164     template <class T>
    165     BaseCommandLineArgument& CommandLine::addCommandLineArgument(const std::string& name,
    166                                              const T& defaultValue)
     288    /**
     289    @brief
     290        Adds a new CommandLineArgument to the internal map.
     291        Note that only such arguments are actually valid.
     292    @param name
     293        Name of the argument. Shortcut can be added later.
     294    @param defaultValue
     295        Default value that is used when argument was not given.
     296    @note
     297        In order to store char* strings as std::string too, there's
     298        little bit of template programming involved:
     299        StaticConversions::exists determines whether T converts to std::string.
     300        Int2Type<int> is then used to call the right function. One returns
     301        a CommandLineArgument<T> and the other CommandLineArgument<std::string>.
     302    */
     303    template <class T>
     304    BaseCommandLineArgument& CommandLine::addCommandLineArgument(const std::string& name, T defaultValue)
    167305    {
    168306        std::map<std::string, BaseCommandLineArgument*>::const_iterator it = _getInstance().cmdLineArgs_.find(name);
     
    170308            "Cannot add a command line argument with name '" + name + "' twice.");
    171309
    172         return *(_getInstance().cmdLineArgs_[name] = new CommandLineArgument<T>(name, defaultValue));
     310        return *(_getInstance().cmdLineArgs_[name] =
     311            _getInstance().createArg(name, defaultValue, Int2Type<StaticConversion<T, std::string>::exists>()));
     312    }
     313
     314    /**
     315        Returns a new CommandLineArgument<T>.
     316    */
     317    template <class T>
     318    BaseCommandLineArgument* CommandLine::createArg(const std::string& name, T defaultValue, Int2Type<0> isPrime)
     319    {
     320        return new CommandLineArgument<T>(name, defaultValue);
     321    }
     322
     323    /**
     324        Returns a new CommandLineArgument<std::string>.
     325    */
     326    template <class T>
     327    BaseCommandLineArgument* CommandLine::createArg(const std::string& name, T defaultValue, Int2Type<1> isPrime)
     328    {
     329        return new CommandLineArgument<std::string>(name, defaultValue);
    173330    }
    174331}
Note: See TracChangeset for help on using the changeset viewer.