Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/pch/src/core/CommandLine.cc @ 3151

Last change on this file since 3151 was 3150, checked in by rgrieder, 15 years ago

Build fixes (X11 defines the None macro…)

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