root/OpenSceneGraph/branches/OpenSceneGraph-2.8/src/osg/ArgumentParser.cpp @ 10413

Revision 10413, 19.0 kB (checked in by robert, 5 years ago)

From Mathias Froehlich, changes from atof to use osg::asciiToFloat() to avoid locale issues with atof

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under 
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#include <stdlib.h>
15#include <string.h>
16
17#include <osg/ArgumentParser>
18#include <osg/ApplicationUsage>
19#include <osg/Math>
20#include <osg/Notify>
21
22#include <set>
23#include <iostream>
24
25using namespace osg;
26
27bool ArgumentParser::isOption(const char* str)
28{
29    return str && str[0]=='-';
30}
31
32bool ArgumentParser::isString(const char* str)
33{
34    if (!str) return false;
35    return true;
36    //return !isOption(str);
37}
38
39bool ArgumentParser::isBool(const char* str)
40{
41    if (!str) return false;
42
43    return (strcmp(str,"True")==0 || strcmp(str,"true")==0 || strcmp(str,"TRUE")==0 ||
44            strcmp(str,"False")==0 || strcmp(str,"false")==0 || strcmp(str,"FALSE")==0 ||
45            strcmp(str,"0")==0 || strcmp(str,"1")==0);
46}
47
48bool ArgumentParser::isNumber(const char* str)
49{
50    if (!str) return false;
51
52    bool hadPlusMinus = false;
53    bool hadDecimalPlace = false;
54    bool hadExponent = false;
55    bool couldBeInt = true;
56    bool couldBeFloat = true;
57    int noZeroToNine = 0;
58
59    const char* ptr = str;
60   
61    // check if could be a hex number.
62    if (strncmp(ptr,"0x",2)==0)
63    {
64        // skip over leading 0x, and then go through rest of string
65        // checking to make sure all values are 0...9 or a..f.
66        ptr+=2;
67        while (
68               *ptr!=0 &&
69               ((*ptr>='0' && *ptr<='9') ||
70                (*ptr>='a' && *ptr<='f') || 
71                (*ptr>='A' && *ptr<='F'))
72              )
73        {
74            ++ptr;
75        }
76       
77        // got to end of string without failure, therefore must be a hex integer.
78        if (*ptr==0) return true;
79    }
80   
81    ptr = str;
82
83    // check if a float or an int.
84    while (*ptr!=0 && couldBeFloat)
85    {
86        if (*ptr=='+' || *ptr=='-')
87        {
88            if (hadPlusMinus)
89            {
90                couldBeInt = false;
91                couldBeFloat = false;
92            } else hadPlusMinus = true;
93        }
94        else if (*ptr>='0' && *ptr<='9')
95        {
96            noZeroToNine++;
97        }
98        else if (*ptr=='.')
99        {
100            if (hadDecimalPlace)
101            {
102                couldBeInt = false;
103                couldBeFloat = false;
104            }
105            else
106            {
107                hadDecimalPlace = true;
108                couldBeInt = false;
109            }
110        }
111        else if (*ptr=='e' || *ptr=='E')
112        {
113            if (hadExponent || noZeroToNine==0)
114            {
115                couldBeInt = false;
116                couldBeFloat = false;
117            }
118            else
119            {
120                hadExponent = true;
121                couldBeInt = false;
122                hadDecimalPlace = false;
123                hadPlusMinus = false;
124                noZeroToNine=0;
125            }
126        }
127        else
128        {
129            couldBeInt = false;
130            couldBeFloat = false;
131        }
132        ++ptr;
133    }
134
135    if (couldBeInt && noZeroToNine>0) return true;
136    if (couldBeFloat && noZeroToNine>0) return true;
137
138    return false;
139   
140}
141
142bool ArgumentParser::Parameter::valid(const char* str) const
143{
144    switch(_type)
145    {
146    case Parameter::BOOL_PARAMETER:         return isBool(str); break;
147    case Parameter::FLOAT_PARAMETER:        return isNumber(str); break;
148    case Parameter::DOUBLE_PARAMETER:       return isNumber(str); break;
149    case Parameter::INT_PARAMETER:          return isNumber(str); break;
150    case Parameter::UNSIGNED_INT_PARAMETER: return isNumber(str); break;
151    case Parameter::STRING_PARAMETER:       return isString(str); break;
152    }
153    return false;
154}
155
156bool ArgumentParser::Parameter::assign(const char* str)
157{
158    if (valid(str))
159    {
160        switch(_type)
161        {
162        case Parameter::BOOL_PARAMETER:
163        {
164            *_value._bool =  (strcmp(str,"True")==0 || strcmp(str,"true")==0 || strcmp(str,"TRUE")==0);
165            break;
166        }
167        case Parameter::FLOAT_PARAMETER:        *_value._float = osg::asciiToFloat(str); break;
168        case Parameter::DOUBLE_PARAMETER:       *_value._double = osg::asciiToDouble(str); break;
169        case Parameter::INT_PARAMETER:          *_value._int = atoi(str); break;
170        case Parameter::UNSIGNED_INT_PARAMETER: *_value._uint = atoi(str); break;
171        case Parameter::STRING_PARAMETER:       *_value._string = str; break;
172        }
173        return true;
174    }
175    else
176    {
177        return false;
178    }
179}
180
181
182
183ArgumentParser::ArgumentParser(int* argc,char **argv):
184    _argc(argc),
185    _argv(argv),
186    _usage(ApplicationUsage::instance())
187{
188#ifdef __APPLE__
189    //On OSX, any -psn arguments need to be removed because they will
190    // confuse the application. -psn plus a concatenated argument are
191    // passed by the finder to application bundles
192    for(int pos=1;pos<this->argc();++pos)
193    {
194        if (std::string(_argv[pos]).compare(0, 4, std::string("-psn")) == 0)
195        {
196            remove(pos, 1);
197        }
198    }
199#endif
200}
201
202std::string ArgumentParser::getApplicationName() const
203{
204    if (_argc && *_argc>0 ) return std::string(_argv[0]);
205    return "";
206}
207
208 
209bool ArgumentParser::isOption(int pos) const
210{
211    return pos<*_argc && isOption(_argv[pos]);
212}
213
214bool ArgumentParser::isString(int pos) const
215{
216    return pos < *_argc && isString(_argv[pos]);
217}
218
219bool ArgumentParser::isNumber(int pos) const
220{
221    return pos < *_argc && isNumber(_argv[pos]);
222}
223
224
225int ArgumentParser::find(const std::string& str) const
226{
227    for(int pos=1;pos<*_argc;++pos)
228    {
229        if (str==_argv[pos])
230        {
231            return pos;
232        }
233    }
234    return -1;
235}
236
237bool ArgumentParser::match(int pos, const std::string& str) const
238{
239    return pos<*_argc && str==_argv[pos];
240}
241
242
243bool ArgumentParser::containsOptions() const
244{
245    for(int pos=1;pos<*_argc;++pos)
246    {
247        if (isOption(pos)) return true;
248    }
249    return false;
250}
251
252
253void ArgumentParser::remove(int pos,int num)
254{
255    if (num==0) return;
256   
257    for(;pos+num<*_argc;++pos)
258    {
259        _argv[pos]=_argv[pos+num];
260    }
261    for(;pos<*_argc;++pos)
262    {
263        _argv[pos]=0;
264    }
265    *_argc-=num;
266}
267
268bool ArgumentParser::read(const std::string& str)
269{
270    int pos=find(str);
271    if (pos<=0) return false;
272    remove(pos);
273    return true;
274}
275
276bool ArgumentParser::read(const std::string& str, Parameter value1)
277{
278    int pos=find(str);
279    if (pos<=0) return false;
280    return read(pos,str,value1);
281}
282
283bool ArgumentParser::read(const std::string& str, Parameter value1, Parameter value2)
284{
285    int pos=find(str);
286    if (pos<=0) return false;
287    return read(pos,str,value1, value2);
288}
289
290bool ArgumentParser::read(const std::string& str, Parameter value1, Parameter value2, Parameter value3)
291{
292    int pos=find(str);
293    if (pos<=0) return false;
294    return read(pos,str,value1, value2, value3);
295}
296
297bool ArgumentParser::read(const std::string& str, Parameter value1, Parameter value2, Parameter value3, Parameter value4)
298{
299    int pos=find(str);
300    if (pos<=0) return false;
301    return read(pos,str,value1, value2, value3, value4);
302}
303
304bool ArgumentParser::read(const std::string& str, Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5)
305{
306    int pos=find(str);
307    if (pos<=0) return false;
308    return read(pos,str,value1, value2, value3, value4, value5);
309}
310
311bool ArgumentParser::read(const std::string& str, Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5, Parameter value6)
312{
313    int pos=find(str);
314    if (pos<=0) return false;
315    return read(pos,str,value1, value2, value3, value4, value5, value6);
316}
317
318bool ArgumentParser::read(const std::string& str, Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5, Parameter value6, Parameter value7)
319{
320    int pos=find(str);
321    if (pos<=0) return false;
322    return read(pos,str,value1, value2, value3, value4, value5, value6, value7);
323}
324
325bool ArgumentParser::read(const std::string& str, Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5, Parameter value6, Parameter value7, Parameter value8)
326{
327    int pos=find(str);
328    if (pos<=0) return false;
329    return read(pos,str,value1, value2, value3, value4, value5, value6, value7, value8);
330}
331
332/** if the argument value at the position pos matches specified string, and subsequent
333  * Parameters are also matched then set the Parameter values and remove the from the list of arguments.*/
334bool ArgumentParser::read(int pos, const std::string& str)
335{
336    if (match(pos,str))
337    {
338        remove(pos,1);
339        return true;
340    }
341    return false;
342}
343
344bool ArgumentParser::read(int pos, const std::string& str, Parameter value1)
345{
346    if (match(pos,str))
347    {
348        if ((pos+1)<*_argc)
349        {
350            if (value1.valid(_argv[pos+1]))
351            {
352                value1.assign(_argv[pos+1]);
353                remove(pos,2);
354                return true;
355            }
356            reportError("argument to `"+str+"` is not valid");
357            return false;
358        }
359        reportError("argument to `"+str+"` is missing");
360        return false;
361    }
362    return false;
363}
364
365bool ArgumentParser::read(int pos, const std::string& str, Parameter value1, Parameter value2)
366{
367    if (match(pos,str))
368    {
369        if ((pos+2)<*_argc)
370        {
371            if (value1.valid(_argv[pos+1]) &&
372                value2.valid(_argv[pos+2]))
373            {
374                value1.assign(_argv[pos+1]);
375                value2.assign(_argv[pos+2]);
376                remove(pos,3);
377                return true;
378            }
379            reportError("argument to `"+str+"` is not valid");
380            return false;
381        }
382        reportError("argument to `"+str+"` is missing");
383        return false;
384    }
385    return false;
386}
387
388bool ArgumentParser::read(int pos, const std::string& str, Parameter value1, Parameter value2, Parameter value3)
389{
390    if (match(pos,str))
391    {
392        if ((pos+3)<*_argc)
393        {
394            if (value1.valid(_argv[pos+1]) &&
395                value2.valid(_argv[pos+2]) &&
396                value3.valid(_argv[pos+3]))
397            {
398                value1.assign(_argv[pos+1]);
399                value2.assign(_argv[pos+2]);
400                value3.assign(_argv[pos+3]);
401                remove(pos,4);
402                return true;
403            }
404            reportError("argument to `"+str+"` is not valid");
405            return false;
406        }
407        reportError("argument to `"+str+"` is missing");
408        return false;
409    }
410    return false;
411}
412
413bool ArgumentParser::read(int pos, const std::string& str, Parameter value1, Parameter value2, Parameter value3, Parameter value4)
414{
415    if (match(pos,str))
416    {
417        if ((pos+4)<*_argc)
418        {
419            if (value1.valid(_argv[pos+1]) &&
420                value2.valid(_argv[pos+2]) &&
421                value3.valid(_argv[pos+3]) &&
422                value4.valid(_argv[pos+4]))
423            {
424                value1.assign(_argv[pos+1]);
425                value2.assign(_argv[pos+2]);
426                value3.assign(_argv[pos+3]);
427                value4.assign(_argv[pos+4]);
428                remove(pos,5);
429                return true;
430            }
431            reportError("argument to `"+str+"` is not valid");
432            return false;
433        }
434        reportError("argument to `"+str+"` is missing");
435        return false;
436    }
437    return false;
438}
439
440bool ArgumentParser::read(int pos, const std::string& str, Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5)
441{
442    if (match(pos,str))
443    {
444        if ((pos+5)<*_argc)
445        {
446            if (value1.valid(_argv[pos+1]) &&
447                value2.valid(_argv[pos+2]) &&
448                value3.valid(_argv[pos+3]) &&
449                value4.valid(_argv[pos+4]) &&
450                value5.valid(_argv[pos+5]))
451            {
452                value1.assign(_argv[pos+1]);
453                value2.assign(_argv[pos+2]);
454                value3.assign(_argv[pos+3]);
455                value4.assign(_argv[pos+4]);
456                value5.assign(_argv[pos+5]);
457                remove(pos,6);
458                return true;
459            }
460            reportError("argument to `"+str+"` is not valid");
461            return false;
462        }
463        reportError("argument to `"+str+"` is missing");
464        return false;
465    }
466    return false;
467}
468
469bool ArgumentParser::read(int pos, const std::string& str, Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5, Parameter value6)
470{
471    if (match(pos,str))
472    {
473        if ((pos+6)<*_argc)
474        {
475            if (value1.valid(_argv[pos+1]) &&
476                value2.valid(_argv[pos+2]) &&
477                value3.valid(_argv[pos+3]) &&
478                value4.valid(_argv[pos+4]) &&
479                value5.valid(_argv[pos+5]) &&
480                value6.valid(_argv[pos+6]))
481            {
482                value1.assign(_argv[pos+1]);
483                value2.assign(_argv[pos+2]);
484                value3.assign(_argv[pos+3]);
485                value4.assign(_argv[pos+4]);
486                value5.assign(_argv[pos+5]);
487                value6.assign(_argv[pos+6]);
488                remove(pos,7);
489                return true;
490            }
491            reportError("argument to `"+str+"` is not valid");
492            return false;
493        }
494        reportError("argument to `"+str+"` is missing");
495        return false;
496    }
497    return false;
498}
499
500bool ArgumentParser::read(int pos, const std::string& str, Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5,  Parameter value6,  Parameter value7)
501{
502    if (match(pos,str))
503    {
504        if ((pos+7)<*_argc)
505        {
506            if (value1.valid(_argv[pos+1]) &&
507                value2.valid(_argv[pos+2]) &&
508                value3.valid(_argv[pos+3]) &&
509                value4.valid(_argv[pos+4]) &&
510                value5.valid(_argv[pos+5]) &&
511                value6.valid(_argv[pos+6]) &&
512                value7.valid(_argv[pos+7]))
513            {
514                value1.assign(_argv[pos+1]);
515                value2.assign(_argv[pos+2]);
516                value3.assign(_argv[pos+3]);
517                value4.assign(_argv[pos+4]);
518                value5.assign(_argv[pos+5]);
519                value6.assign(_argv[pos+6]);
520                value7.assign(_argv[pos+7]);
521                remove(pos,8);
522                return true;
523            }
524            reportError("argument to `"+str+"` is not valid");
525            return false;
526        }
527        reportError("argument to `"+str+"` is missing");
528        return false;
529    }
530    return false;
531}
532
533bool ArgumentParser::read(int pos, const std::string& str, Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5,  Parameter value6,  Parameter value7,  Parameter value8)
534{
535    if (match(pos,str))
536    {
537        if ((pos+8)<*_argc)
538        {
539            if (value1.valid(_argv[pos+1]) &&
540                value2.valid(_argv[pos+2]) &&
541                value3.valid(_argv[pos+3]) &&
542                value4.valid(_argv[pos+4]) &&
543                value5.valid(_argv[pos+5]) &&
544                value6.valid(_argv[pos+6]) &&
545                value7.valid(_argv[pos+7]) &&
546                value8.valid(_argv[pos+8]))
547            {
548                value1.assign(_argv[pos+1]);
549                value2.assign(_argv[pos+2]);
550                value3.assign(_argv[pos+3]);
551                value4.assign(_argv[pos+4]);
552                value5.assign(_argv[pos+5]);
553                value6.assign(_argv[pos+6]);
554                value7.assign(_argv[pos+7]);
555                value8.assign(_argv[pos+8]);
556                remove(pos,9);
557                return true;
558            }
559            reportError("argument to `"+str+"` is not valid");
560            return false;
561        }
562        reportError("argument to `"+str+"` is missing");
563        return false;
564    }
565    return false;
566}
567
568bool ArgumentParser::errors(ErrorSeverity severity) const
569{
570    for(ErrorMessageMap::const_iterator itr=_errorMessageMap.begin();
571        itr!=_errorMessageMap.end();
572        ++itr)
573    {
574        if (itr->second>=severity) return true;
575    }
576    return false;
577}
578
579void ArgumentParser::reportError(const std::string& message,ErrorSeverity severity)
580{
581    _errorMessageMap[message]=severity;
582}
583
584void ArgumentParser::reportRemainingOptionsAsUnrecognized(ErrorSeverity severity)
585{
586    std::set<std::string> options;
587    if (_usage.valid())
588    {
589        // parse the usage options to get all the option that the application can potential handle.
590        for(ApplicationUsage::UsageMap::const_iterator itr=_usage->getCommandLineOptions().begin();
591            itr!=_usage->getCommandLineOptions().end();
592            ++itr)
593        {
594            const std::string& option = itr->first;
595            std::string::size_type prevpos = 0, pos = 0;
596            while ((pos=option.find(' ',prevpos))!=std::string::npos)
597            {
598                if (option[prevpos]=='-')
599                {
600                    options.insert(std::string(option,prevpos,pos-prevpos));
601                }
602                prevpos=pos+1;
603            }
604            if (option[prevpos]=='-')
605            {
606
607                options.insert(std::string(option,prevpos,std::string::npos));
608            }
609        }
610       
611    }
612
613    for(int pos=1;pos<argc();++pos)
614    {
615        // if an option and havn't been previous querried for report as unrecognized.
616        if (isOption(pos) && options.find(_argv[pos])==options.end())
617        {
618            reportError(std::string("unrecognized option ")+std::string(_argv[pos]),severity);
619        }
620    }
621}
622void ArgumentParser::writeErrorMessages(std::ostream& output,ErrorSeverity severity)
623{
624    for(ErrorMessageMap::iterator itr=_errorMessageMap.begin();
625        itr!=_errorMessageMap.end();
626        ++itr)
627    {
628        if (itr->second>=severity)
629        {
630            output<< getApplicationName() << ": " << itr->first << std::endl;
631        }
632    }
633}
634
635ApplicationUsage::Type ArgumentParser::readHelpType()
636{
637    getApplicationUsage()->addCommandLineOption("-h or --help","Display command line parameters");
638    getApplicationUsage()->addCommandLineOption("--help-env","Display environmental variables available");
639    getApplicationUsage()->addCommandLineOption("--help-keys","Display keyboard & mouse bindings available");
640    getApplicationUsage()->addCommandLineOption("--help-all","Display all command line, env vars and keyboard & mouse bindings.");
641
642    // if user request help write it out to cout.
643    if (read("--help-all"))             return ApplicationUsage::HELP_ALL;
644    if (read("-h") || read("--help"))   return ApplicationUsage::COMMAND_LINE_OPTION;
645    if (read("--help-env"))             return ApplicationUsage::ENVIRONMENTAL_VARIABLE;
646    if (read("--help-keys"))            return ApplicationUsage::KEYBOARD_MOUSE_BINDING;
647
648    return ApplicationUsage::NO_HELP;
649}
Note: See TracBrowser for help on using the browser.