Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/trunk/src/core/CommandLine.cc @ 2708

Last change on this file since 2708 was 2662, checked in by rgrieder, 16 years ago

Merged presentation branch back to trunk.

  • Property svn:eol-style set to native
File size: 10.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#include "util/SubString.h"
33
34namespace orxonox
35{
36    SetCommandLineArgument(optionsFile, "start.ini").shortcut("o");
37
38    /**
39    @brief
40        Parses a value string for a command line argument.
41        It simply uses convertValue(Output, Input) to do that.
42        Bools are treated specially. That is necessary
43        so that you can have simple command line switches.
44    */
45    void CommandLineArgument::parse(const std::string& value)
46    {
47        if (value_.getType() == MT_bool)
48        {
49            // simulate command line switch
50            bool temp;
51            if (convertValue(&temp, value))
52            {
53                this->bHasDefaultValue_ = false;
54                this->value_ = temp;
55            }
56            else if (value == "")
57            {
58                this->bHasDefaultValue_ = false;
59                this->value_ = true;
60            }
61            else
62            {
63                ThrowException(Argument, "Could not read command line argument '" + getName() + "'.");
64            }
65        }
66        else
67        {
68            if (!value_.setValue(value))
69            {
70                value_.setValue(defaultValue_);
71                ThrowException(Argument, "Could not read command line argument '" + getName() + "'.");
72            }
73            else
74                this->bHasDefaultValue_ = false;
75        }
76    }
77
78
79    /**
80    @brief
81        Destructor destroys all CommandLineArguments with it.
82    */
83    CommandLine::~CommandLine()
84    {
85        CommandLine::destroyAllArguments();
86    }
87
88    /**
89    @brief
90        Returns a unique instance (Meyers Singleton).
91    */
92    CommandLine& CommandLine::_getInstance()
93    {
94        static CommandLine instance;
95        return instance;
96    }
97
98    /**
99    @brief
100        Destroys all command line arguments. This should be called at the end
101        of main. Do not use before that.
102    */
103    void CommandLine::destroyAllArguments()
104    {
105        for (std::map<std::string, CommandLineArgument*>::const_iterator it = _getInstance().cmdLineArgs_.begin();
106            it != _getInstance().cmdLineArgs_.end(); ++it)
107            delete it->second;
108        _getInstance().cmdLineArgs_.clear();
109    }
110
111    /**
112    @brief
113        Reads the command line parses the values of each argument.
114        It is then stored in the corresponding CommandLineArgument.
115    @note
116        The reason that you have to provide the string to be parsed as
117        space separted list is because of argc and argv. If you only have
118        a whole string, simply use getAllStrings() of SubString.
119    @param arguments
120        Vector of space separated strings.
121    */
122    void CommandLine::_parse(const std::vector<std::string>& arguments)
123    {
124        // why this? See bFirstTimeParse_ declaration.
125        if (bFirstTimeParse_)
126        {
127            // first shove all the shortcuts in a map
128            for (std::map<std::string, CommandLineArgument*>::const_iterator it = cmdLineArgs_.begin();
129                it != cmdLineArgs_.end(); ++it)
130            {
131                OrxAssert(cmdLineArgsShortcut_.find(it->second->getShortcut()) == cmdLineArgsShortcut_.end(),
132                    "Cannot have two command line shortcut with the same name.");
133                if (it->second->getShortcut() != "")
134                    cmdLineArgsShortcut_[it->second->getShortcut()] = it->second;
135            }
136            bFirstTimeParse_ = false;
137        }
138
139        std::string name;
140        std::string shortcut;
141        std::string value;
142        for (unsigned int i = 0; i < arguments.size(); ++i)
143        {
144            if (arguments[i].size() != 0)
145            {
146                // sure not ""
147                if (arguments[i][0] == '-')
148                {
149                    // start with "-"
150                    if (arguments[i].size() == 1)
151                    {
152                        // argument[i] is "-", probably a minus sign
153                        value += "- ";
154                    }
155                    else if (arguments[i][1] <= 57 && arguments[i][1] >= 48)
156                    {
157                        // negative number as a value
158                        value += arguments[i] + " ";
159                    }
160                    else
161                    {
162                        // can be shortcut or full name argument
163
164                        // save old data first
165                        value = removeTrailingWhitespaces(value);
166                        if (name != "")
167                        {
168                            checkFullArgument(name, value);
169                            name = "";
170                            assert(shortcut == "");
171                        }
172                        else if (shortcut != "")
173                        {
174                            checkShortcut(shortcut, value);
175                            shortcut = "";
176                            assert(name == "");
177                        }
178
179                        if (arguments[i][1] == '-')
180                        {
181                            // full name argument with "--name"
182                            name = arguments[i].substr(2);
183                        }
184                        else
185                        {
186                            // shortcut with "-s"
187                            shortcut = arguments[i].substr(1);
188                        }
189
190                        // reset value string
191                        value = "";
192                    }
193                }
194                else
195                {
196                    // value string
197
198                    if (name == "" && shortcut == "")
199                    {
200                        ThrowException(Argument, "Expected \"-\" or \"-\" in command line arguments.\n");
201                    }
202
203                    // Concatenate strings as long as there's no new argument by "-" or "--"
204                    value += arguments[i] + ' ';
205                }
206            }
207        }
208
209        // parse last argument
210        value = removeTrailingWhitespaces(value);
211        if (name != "")
212        {
213            checkFullArgument(name, value);
214            assert(shortcut == "");
215        }
216        else if (shortcut != "")
217        {
218            checkShortcut(shortcut, value);
219            assert(name == "");
220        }
221    }
222
223    /**
224    @brief
225        Parses an argument based on its full name.
226    @param name
227        Full name of the argument
228    @param value
229        String containing the value
230    */
231    void CommandLine::checkFullArgument(const std::string& name, const std::string& value)
232    {
233        std::map<std::string, CommandLineArgument*>::const_iterator it = cmdLineArgs_.find(name);
234        if (it == cmdLineArgs_.end())
235            ThrowException(Argument, "Command line argument '" + name + "' does not exist.");
236
237        it->second->parse(value);
238    }
239
240    /**
241    @brief
242        Parses an argument based on its shortcut.
243    @param shortcut
244        Shotcut to the argument
245    @param value
246        String containing the value
247    */
248    void CommandLine::checkShortcut(const std::string& shortcut, const std::string& value)
249    {
250        std::map<std::string, CommandLineArgument*>::const_iterator it = cmdLineArgsShortcut_.find(shortcut);
251        if (it == cmdLineArgsShortcut_.end())
252            ThrowException(Argument, "Command line shortcut '" + shortcut + "' does not exist.");
253
254        it->second->parse(value);
255    }
256
257    std::string CommandLine::getUsageInformation()
258    {
259        CommandLine* inst = &_getInstance();
260        std::string infoStr;
261        for (std::map<std::string, CommandLineArgument*>::const_iterator it = inst->cmdLineArgs_.begin();
262            it != inst->cmdLineArgs_.end(); ++it)
263        {
264            infoStr += "[--" + it->second->getName() + " " + it->second->getInformation() + "] ";
265        }
266        return infoStr;
267    }
268
269    /**
270    @brief
271        Retrieves a CommandLineArgument.
272        The method throws an exception if 'name' was not found or the value could not be converted.
273    @note
274        You shold of course not call this method before the command line has been parsed.
275    */
276    const CommandLineArgument* CommandLine::getArgument(const std::string& name)
277    {
278        std::map<std::string, CommandLineArgument*>::const_iterator it = _getInstance().cmdLineArgs_.find(name);
279        if (it == _getInstance().cmdLineArgs_.end())
280        {
281            ThrowException(Argument, "Could find command line argument '" + name + "'.");
282        }
283        else
284        {
285            return it->second;
286        }
287    }
288
289    /**
290    @brief
291        Parses both command line and start.ini for CommandLineArguments.
292    */
293    void CommandLine::_parseAll(int argc, char** argv)
294    {
295        // parse command line first
296        std::vector<std::string> args;
297        for (int i = 1; i < argc; ++i)
298            args.push_back(argv[i]);
299        this->_parse(args);
300
301        // look for additional arguments in given file or start.ini as default
302        // They will not overwrite the arguments given directly
303        std::ifstream file;
304        std::string filename = CommandLine::getValue("optionsFile").getString();
305        file.open(filename.c_str());
306        args.clear();
307        if (file)
308        {
309            while (!file.eof())
310            {
311                std::string line;
312                std::getline(file, line);
313                line = removeTrailingWhitespaces(line);
314                //if (!(line[0] == '#' || line[0] == '%'))
315                //{
316                SubString tokens(line, " ", " ", false, 92, false, 34, false, 40, 41, false, '#');
317                for (unsigned i = 0; i < tokens.size(); ++i)
318                    if (tokens[i][0] != '#')
319                        args.push_back(tokens[i]);
320                //args.insert(args.end(), tokens.getAllStrings().begin(), tokens.getAllStrings().end());
321                //}
322            }
323            file.close();
324        }
325
326        try
327        {
328            _parse(args);
329        }
330        catch (orxonox::ArgumentException& ex)
331        {
332            COUT(1) << "An Exception occured while parsing " << filename << std::endl;
333            throw(ex);
334        }
335    }
336}
Note: See TracBrowser for help on using the repository browser.