Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/objecthierarchy/src/core/CommandLine.cc @ 2051

Last change on this file since 2051 was 2003, checked in by rgrieder, 16 years ago

Simplified CommandLineArgument by using the new MultiType.
That also enables to get a cmd argument even if you don't know the exact type. It simply gets converted.

  • Property svn:eol-style set to native
File size: 8.9 KB
Line 
1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *                    > www.orxonox.net <
4 *
5 *
6 *   License notice:
7 *
8 *   This program is free software; you can redistribute it and/or
9 *   modify it under the terms of the GNU General Public License
10 *   as published by the Free Software Foundation; either version 2
11 *   of the License, or (at your option) any later version.
12 *
13 *   This program is distributed in the hope that it will be useful,
14 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
15 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 *   GNU General Public License for more details.
17 *
18 *   You should have received a copy of the GNU General Public License
19 *   along with this program; if not, write to the Free Software
20 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
21 *
22 *   Author:
23 *      Reto Grieder
24 *   Co-authors:
25 *      ...
26 *
27 */
28
29#include "CommandLine.h"
30
31#include "util/String.h"
32
33namespace orxonox
34{
35    /**
36    @brief
37        Parses a value string for a command line argument.
38        It simply uses convertValue(Output, Input) to do that.
39        Bools are treated specially. That is necessary
40        so that you can have simple command line switches.
41    */
42    void CommandLineArgument::parse(const std::string& value)
43    {
44        if (value_.getType() == MT_bool)
45        {
46            // simulate command line switch
47            bool temp;
48            if (convertValue(&temp, value))
49            {
50                this->bHasDefaultValue_ = false;
51                this->value_ = temp;
52            }
53            else if (value == "")
54            {
55                this->bHasDefaultValue_ = false;
56                this->value_ = true;
57            }
58            else
59            {
60                ThrowException(Argument, "Could not read command line argument '" + getName() + "'.");
61            }
62        }
63        else
64        {
65            if (!value_.setValue(value))
66            {
67                value_.setValue(defaultValue_);
68                ThrowException(Argument, "Could not read command line argument '" + getName() + "'.");
69            }
70            else
71                this->bHasDefaultValue_ = false;
72        }
73    }
74
75
76    /**
77    @brief
78        Destructor destroys all CommandLineArguments with it.
79    */
80    CommandLine::~CommandLine()
81    {
82        for (std::map<std::string, CommandLineArgument*>::const_iterator it = cmdLineArgs_.begin();
83            it != cmdLineArgs_.end(); ++it)
84        {
85            delete it->second;
86        }
87    }
88
89    /**
90    @brief
91        Returns a unique instance (Meyers Singleton).
92    */
93    CommandLine& CommandLine::_getInstance()
94    {
95        static CommandLine instance;
96        return instance;
97    }
98
99    /**
100    @brief
101        Reads the command line parses the values of each argument.
102        It is then stored in the corresponding CommandLineArgument.
103    @note
104        The reason that you have to provide the string to be parsed as
105        space separted list is because of argc and argv. If you only have
106        a whole string, simply use getAllStrings() of SubString.
107    @param arguments
108        Vector of space separated strings.
109    */
110    void CommandLine::_parse(const std::vector<std::string>& arguments)
111    {
112        // why this? See bFirstTimeParse_ declaration.
113        if (bFirstTimeParse_)
114        {
115            // first shove all the shortcuts in a map
116            for (std::map<std::string, CommandLineArgument*>::const_iterator it = cmdLineArgs_.begin();
117                it != cmdLineArgs_.end(); ++it)
118            {
119                OrxAssert(cmdLineArgsShortcut_.find(it->second->getShortcut()) == cmdLineArgsShortcut_.end(),
120                    "Cannot have two command line shortcut with the same name.");
121                if (it->second->getShortcut() != "")
122                    cmdLineArgsShortcut_[it->second->getShortcut()] = it->second;
123            }
124            bFirstTimeParse_ = false;
125        }
126
127        std::string name;
128        std::string shortcut;
129        std::string value;
130        for (unsigned int i = 0; i < arguments.size(); ++i)
131        {
132            if (arguments[i].size() != 0)
133            {
134                // sure not ""
135                if (arguments[i][0] == '-')
136                {
137                    // start with "-"
138                    if (arguments[i].size() == 1)
139                    {
140                        // argument[i] is "-", probably a minus sign
141                        value += "- ";
142                    }
143                    else if (arguments[i][1] <= 57 && arguments[i][1] >= 48)
144                    {
145                        // negative number as a value
146                        value += arguments[i] + " ";
147                    }
148                    else
149                    {
150                        // can be shortcut or full name argument
151
152                        // save old data first
153                        value = removeTrailingWhitespaces(value);
154                        if (name != "")
155                        {
156                            checkFullArgument(name, value);
157                            name = "";
158                            assert(shortcut == "");
159                        }
160                        else if (shortcut != "")
161                        {
162                            checkShortcut(shortcut, value);
163                            shortcut = "";
164                            assert(name == "");
165                        }
166
167                        if (arguments[i][1] == '-')
168                        {
169                            // full name argument with "--name"
170                            name = arguments[i].substr(2);
171                        }
172                        else
173                        {
174                            // shortcut with "-s"
175                            shortcut = arguments[i].substr(1);
176                        }
177
178                        // reset value string
179                        value = "";
180                    }
181                }
182                else
183                {
184                    // value string
185
186                    if (name == "" && shortcut == "")
187                    {
188                        ThrowException(Argument, "Expected \"-\" or \"-\" in command line arguments.\n");
189                    }
190
191                    // Concatenate strings as long as there's no new argument by "-" or "--"
192                    value += arguments[i] + ' ';
193                }
194            }
195        }
196
197        // parse last argument
198        value = removeTrailingWhitespaces(value);
199        if (name != "")
200        {
201            checkFullArgument(name, value);
202            assert(shortcut == "");
203        }
204        else if (shortcut != "")
205        {
206            checkShortcut(shortcut, value);
207            assert(name == "");
208        }
209    }
210
211    /**
212    @brief
213        Parses an argument based on its full name.
214    @param name
215        Full name of the argument
216    @param value
217        String containing the value
218    */
219    void CommandLine::checkFullArgument(const std::string& name, const std::string& value)
220    {
221        std::map<std::string, CommandLineArgument*>::const_iterator it = cmdLineArgs_.find(name);
222        if (it == cmdLineArgs_.end())
223            ThrowException(Argument, "Command line argument '" + name + "' does not exist.");
224
225        it->second->parse(value);
226    }
227
228    /**
229    @brief
230        Parses an argument based on its shortcut.
231    @param shortcut
232        Shotcut to the argument
233    @param value
234        String containing the value
235    */
236    void CommandLine::checkShortcut(const std::string& shortcut, const std::string& value)
237    {
238        std::map<std::string, CommandLineArgument*>::const_iterator it = cmdLineArgsShortcut_.find(shortcut);
239        if (it == cmdLineArgsShortcut_.end())
240            ThrowException(Argument, "Command line shortcut '" + shortcut + "' does not exist.");
241
242        it->second->parse(value);
243    }
244
245    std::string CommandLine::getUsageInformation()
246    {
247        CommandLine* inst = &_getInstance();
248        std::string infoStr;
249        for (std::map<std::string, CommandLineArgument*>::const_iterator it = inst->cmdLineArgs_.begin();
250            it != inst->cmdLineArgs_.end(); ++it)
251        {
252            infoStr += "[--" + it->second->getName() + " " + it->second->getInformation() + "] ";
253        }
254        return infoStr;
255    }
256
257    /**
258    @brief
259        Retrieves a CommandLineArgument.
260        The method throws an exception if 'name' was not found or the value could not be converted.
261    @note
262        You shold of course not call this method before the command line has been parsed.
263    */
264    const CommandLineArgument* CommandLine::getArgument(const std::string& name)
265    {
266        std::map<std::string, CommandLineArgument*>::const_iterator it = _getInstance().cmdLineArgs_.find(name);
267        if (it == _getInstance().cmdLineArgs_.end())
268        {
269            ThrowException(Argument, "Could find command line argument '" + name + "'.");
270        }
271        else
272        {
273            return it->second;
274        }
275    }
276}
Note: See TracBrowser for help on using the repository browser.