Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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

Merged r2101 (objecthierarchy) to trunk.

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