Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

Last change on this file since 3034 was 2759, checked in by scheusso, 16 years ago

merged network branch (windows,multiplayer fixes) back to trunk

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