root/OpenSceneGraph/trunk/src/osg/ArgumentParser.cpp @ 10415

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

From Mathias Froehlich, "We are currently getting issues with locale settings and some osg plugins.
Therefore I have changed all the occurances of atof by asciiToFloat or
asciiToDouble.

I believe that it is safe to do so at least for all the plugins.
Included here are also asciiToFloat conversion of environment variables. One
might argue that these should be locale dependent. But IMO these should be
set and interpreted by osg independent of the current locale.
"

  • 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.