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

Revision 13041, 19.2 kB (checked in by robert, 2 years ago)

Ran script to remove trailing spaces and tabs

  • 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#ifdef WIN32
202    // Remove linefeed from last argument if it exist
203    char* lastline = argc==0 ? 0 : _argv[*argc-1];
204    if (lastline)
205    {
206        int len = strlen(lastline);
207        if (len>0 && lastline[len-1] == '\n') lastline[len-1]= '\0';
208    }
209#endif
210}
211
212std::string ArgumentParser::getApplicationName() const
213{
214    if (_argc && *_argc>0 ) return std::string(_argv[0]);
215    return "";
216}
217
218
219bool ArgumentParser::isOption(int pos) const
220{
221    return pos<*_argc && isOption(_argv[pos]);
222}
223
224bool ArgumentParser::isString(int pos) const
225{
226    return pos < *_argc && isString(_argv[pos]);
227}
228
229bool ArgumentParser::isNumber(int pos) const
230{
231    return pos < *_argc && isNumber(_argv[pos]);
232}
233
234
235int ArgumentParser::find(const std::string& str) const
236{
237    for(int pos=1;pos<*_argc;++pos)
238    {
239        if (str==_argv[pos])
240        {
241            return pos;
242        }
243    }
244    return -1;
245}
246
247bool ArgumentParser::match(int pos, const std::string& str) const
248{
249    return pos<*_argc && str==_argv[pos];
250}
251
252
253bool ArgumentParser::containsOptions() const
254{
255    for(int pos=1;pos<*_argc;++pos)
256    {
257        if (isOption(pos)) return true;
258    }
259    return false;
260}
261
262
263void ArgumentParser::remove(int pos,int num)
264{
265    if (num==0) return;
266
267    for(;pos+num<*_argc;++pos)
268    {
269        _argv[pos]=_argv[pos+num];
270    }
271    for(;pos<*_argc;++pos)
272    {
273        _argv[pos]=0;
274    }
275    *_argc-=num;
276}
277
278bool ArgumentParser::read(const std::string& str)
279{
280    int pos=find(str);
281    if (pos<=0) return false;
282    remove(pos);
283    return true;
284}
285
286bool ArgumentParser::read(const std::string& str, Parameter value1)
287{
288    int pos=find(str);
289    if (pos<=0) return false;
290    return read(pos,str,value1);
291}
292
293bool ArgumentParser::read(const std::string& str, Parameter value1, Parameter value2)
294{
295    int pos=find(str);
296    if (pos<=0) return false;
297    return read(pos,str,value1, value2);
298}
299
300bool ArgumentParser::read(const std::string& str, Parameter value1, Parameter value2, Parameter value3)
301{
302    int pos=find(str);
303    if (pos<=0) return false;
304    return read(pos,str,value1, value2, value3);
305}
306
307bool ArgumentParser::read(const std::string& str, Parameter value1, Parameter value2, Parameter value3, Parameter value4)
308{
309    int pos=find(str);
310    if (pos<=0) return false;
311    return read(pos,str,value1, value2, value3, value4);
312}
313
314bool ArgumentParser::read(const std::string& str, Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5)
315{
316    int pos=find(str);
317    if (pos<=0) return false;
318    return read(pos,str,value1, value2, value3, value4, value5);
319}
320
321bool ArgumentParser::read(const std::string& str, Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5, Parameter value6)
322{
323    int pos=find(str);
324    if (pos<=0) return false;
325    return read(pos,str,value1, value2, value3, value4, value5, value6);
326}
327
328bool ArgumentParser::read(const std::string& str, Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5, Parameter value6, Parameter value7)
329{
330    int pos=find(str);
331    if (pos<=0) return false;
332    return read(pos,str,value1, value2, value3, value4, value5, value6, value7);
333}
334
335bool ArgumentParser::read(const std::string& str, Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5, Parameter value6, Parameter value7, Parameter value8)
336{
337    int pos=find(str);
338    if (pos<=0) return false;
339    return read(pos,str,value1, value2, value3, value4, value5, value6, value7, value8);
340}
341
342/** if the argument value at the position pos matches specified string, and subsequent
343  * Parameters are also matched then set the Parameter values and remove the from the list of arguments.*/
344bool ArgumentParser::read(int pos, const std::string& str)
345{
346    if (match(pos,str))
347    {
348        remove(pos,1);
349        return true;
350    }
351    return false;
352}
353
354bool ArgumentParser::read(int pos, const std::string& str, Parameter value1)
355{
356    if (match(pos,str))
357    {
358        if ((pos+1)<*_argc)
359        {
360            if (value1.valid(_argv[pos+1]))
361            {
362                value1.assign(_argv[pos+1]);
363                remove(pos,2);
364                return true;
365            }
366            reportError("argument to `"+str+"` is not valid");
367            return false;
368        }
369        reportError("argument to `"+str+"` is missing");
370        return false;
371    }
372    return false;
373}
374
375bool ArgumentParser::read(int pos, const std::string& str, Parameter value1, Parameter value2)
376{
377    if (match(pos,str))
378    {
379        if ((pos+2)<*_argc)
380        {
381            if (value1.valid(_argv[pos+1]) &&
382                value2.valid(_argv[pos+2]))
383            {
384                value1.assign(_argv[pos+1]);
385                value2.assign(_argv[pos+2]);
386                remove(pos,3);
387                return true;
388            }
389            reportError("argument to `"+str+"` is not valid");
390            return false;
391        }
392        reportError("argument to `"+str+"` is missing");
393        return false;
394    }
395    return false;
396}
397
398bool ArgumentParser::read(int pos, const std::string& str, Parameter value1, Parameter value2, Parameter value3)
399{
400    if (match(pos,str))
401    {
402        if ((pos+3)<*_argc)
403        {
404            if (value1.valid(_argv[pos+1]) &&
405                value2.valid(_argv[pos+2]) &&
406                value3.valid(_argv[pos+3]))
407            {
408                value1.assign(_argv[pos+1]);
409                value2.assign(_argv[pos+2]);
410                value3.assign(_argv[pos+3]);
411                remove(pos,4);
412                return true;
413            }
414            reportError("argument to `"+str+"` is not valid");
415            return false;
416        }
417        reportError("argument to `"+str+"` is missing");
418        return false;
419    }
420    return false;
421}
422
423bool ArgumentParser::read(int pos, const std::string& str, Parameter value1, Parameter value2, Parameter value3, Parameter value4)
424{
425    if (match(pos,str))
426    {
427        if ((pos+4)<*_argc)
428        {
429            if (value1.valid(_argv[pos+1]) &&
430                value2.valid(_argv[pos+2]) &&
431                value3.valid(_argv[pos+3]) &&
432                value4.valid(_argv[pos+4]))
433            {
434                value1.assign(_argv[pos+1]);
435                value2.assign(_argv[pos+2]);
436                value3.assign(_argv[pos+3]);
437                value4.assign(_argv[pos+4]);
438                remove(pos,5);
439                return true;
440            }
441            reportError("argument to `"+str+"` is not valid");
442            return false;
443        }
444        reportError("argument to `"+str+"` is missing");
445        return false;
446    }
447    return false;
448}
449
450bool ArgumentParser::read(int pos, const std::string& str, Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5)
451{
452    if (match(pos,str))
453    {
454        if ((pos+5)<*_argc)
455        {
456            if (value1.valid(_argv[pos+1]) &&
457                value2.valid(_argv[pos+2]) &&
458                value3.valid(_argv[pos+3]) &&
459                value4.valid(_argv[pos+4]) &&
460                value5.valid(_argv[pos+5]))
461            {
462                value1.assign(_argv[pos+1]);
463                value2.assign(_argv[pos+2]);
464                value3.assign(_argv[pos+3]);
465                value4.assign(_argv[pos+4]);
466                value5.assign(_argv[pos+5]);
467                remove(pos,6);
468                return true;
469            }
470            reportError("argument to `"+str+"` is not valid");
471            return false;
472        }
473        reportError("argument to `"+str+"` is missing");
474        return false;
475    }
476    return false;
477}
478
479bool ArgumentParser::read(int pos, const std::string& str, Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5, Parameter value6)
480{
481    if (match(pos,str))
482    {
483        if ((pos+6)<*_argc)
484        {
485            if (value1.valid(_argv[pos+1]) &&
486                value2.valid(_argv[pos+2]) &&
487                value3.valid(_argv[pos+3]) &&
488                value4.valid(_argv[pos+4]) &&
489                value5.valid(_argv[pos+5]) &&
490                value6.valid(_argv[pos+6]))
491            {
492                value1.assign(_argv[pos+1]);
493                value2.assign(_argv[pos+2]);
494                value3.assign(_argv[pos+3]);
495                value4.assign(_argv[pos+4]);
496                value5.assign(_argv[pos+5]);
497                value6.assign(_argv[pos+6]);
498                remove(pos,7);
499                return true;
500            }
501            reportError("argument to `"+str+"` is not valid");
502            return false;
503        }
504        reportError("argument to `"+str+"` is missing");
505        return false;
506    }
507    return false;
508}
509
510bool ArgumentParser::read(int pos, const std::string& str, Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5,  Parameter value6,  Parameter value7)
511{
512    if (match(pos,str))
513    {
514        if ((pos+7)<*_argc)
515        {
516            if (value1.valid(_argv[pos+1]) &&
517                value2.valid(_argv[pos+2]) &&
518                value3.valid(_argv[pos+3]) &&
519                value4.valid(_argv[pos+4]) &&
520                value5.valid(_argv[pos+5]) &&
521                value6.valid(_argv[pos+6]) &&
522                value7.valid(_argv[pos+7]))
523            {
524                value1.assign(_argv[pos+1]);
525                value2.assign(_argv[pos+2]);
526                value3.assign(_argv[pos+3]);
527                value4.assign(_argv[pos+4]);
528                value5.assign(_argv[pos+5]);
529                value6.assign(_argv[pos+6]);
530                value7.assign(_argv[pos+7]);
531                remove(pos,8);
532                return true;
533            }
534            reportError("argument to `"+str+"` is not valid");
535            return false;
536        }
537        reportError("argument to `"+str+"` is missing");
538        return false;
539    }
540    return false;
541}
542
543bool ArgumentParser::read(int pos, const std::string& str, Parameter value1, Parameter value2, Parameter value3, Parameter value4, Parameter value5,  Parameter value6,  Parameter value7,  Parameter value8)
544{
545    if (match(pos,str))
546    {
547        if ((pos+8)<*_argc)
548        {
549            if (value1.valid(_argv[pos+1]) &&
550                value2.valid(_argv[pos+2]) &&
551                value3.valid(_argv[pos+3]) &&
552                value4.valid(_argv[pos+4]) &&
553                value5.valid(_argv[pos+5]) &&
554                value6.valid(_argv[pos+6]) &&
555                value7.valid(_argv[pos+7]) &&
556                value8.valid(_argv[pos+8]))
557            {
558                value1.assign(_argv[pos+1]);
559                value2.assign(_argv[pos+2]);
560                value3.assign(_argv[pos+3]);
561                value4.assign(_argv[pos+4]);
562                value5.assign(_argv[pos+5]);
563                value6.assign(_argv[pos+6]);
564                value7.assign(_argv[pos+7]);
565                value8.assign(_argv[pos+8]);
566                remove(pos,9);
567                return true;
568            }
569            reportError("argument to `"+str+"` is not valid");
570            return false;
571        }
572        reportError("argument to `"+str+"` is missing");
573        return false;
574    }
575    return false;
576}
577
578bool ArgumentParser::errors(ErrorSeverity severity) const
579{
580    for(ErrorMessageMap::const_iterator itr=_errorMessageMap.begin();
581        itr!=_errorMessageMap.end();
582        ++itr)
583    {
584        if (itr->second>=severity) return true;
585    }
586    return false;
587}
588
589void ArgumentParser::reportError(const std::string& message,ErrorSeverity severity)
590{
591    _errorMessageMap[message]=severity;
592}
593
594void ArgumentParser::reportRemainingOptionsAsUnrecognized(ErrorSeverity severity)
595{
596    std::set<std::string> options;
597    if (_usage.valid())
598    {
599        // parse the usage options to get all the option that the application can potential handle.
600        for(ApplicationUsage::UsageMap::const_iterator itr=_usage->getCommandLineOptions().begin();
601            itr!=_usage->getCommandLineOptions().end();
602            ++itr)
603        {
604            const std::string& option = itr->first;
605            std::string::size_type prevpos = 0, pos = 0;
606            while ((pos=option.find(' ',prevpos))!=std::string::npos)
607            {
608                if (option[prevpos]=='-')
609                {
610                    options.insert(std::string(option,prevpos,pos-prevpos));
611                }
612                prevpos=pos+1;
613            }
614            if (option[prevpos]=='-')
615            {
616
617                options.insert(std::string(option,prevpos,std::string::npos));
618            }
619        }
620
621    }
622
623    for(int pos=1;pos<argc();++pos)
624    {
625        // if an option and havn't been previous querried for report as unrecognized.
626        if (isOption(pos) && options.find(_argv[pos])==options.end())
627        {
628            reportError(std::string("unrecognized option ")+std::string(_argv[pos]),severity);
629        }
630    }
631}
632void ArgumentParser::writeErrorMessages(std::ostream& output,ErrorSeverity severity)
633{
634    for(ErrorMessageMap::iterator itr=_errorMessageMap.begin();
635        itr!=_errorMessageMap.end();
636        ++itr)
637    {
638        if (itr->second>=severity)
639        {
640            output<< getApplicationName() << ": " << itr->first << std::endl;
641        }
642    }
643}
644
645ApplicationUsage::Type ArgumentParser::readHelpType()
646{
647    getApplicationUsage()->addCommandLineOption("-h or --help","Display command line parameters");
648    getApplicationUsage()->addCommandLineOption("--help-env","Display environmental variables available");
649    getApplicationUsage()->addCommandLineOption("--help-keys","Display keyboard & mouse bindings available");
650    getApplicationUsage()->addCommandLineOption("--help-all","Display all command line, env vars and keyboard & mouse bindings.");
651
652    // if user request help write it out to cout.
653    if (read("--help-all"))             return ApplicationUsage::HELP_ALL;
654    if (read("-h") || read("--help"))   return ApplicationUsage::COMMAND_LINE_OPTION;
655    if (read("--help-env"))             return ApplicationUsage::ENVIRONMENTAL_VARIABLE;
656    if (read("--help-keys"))            return ApplicationUsage::KEYBOARD_MOUSE_BINDING;
657
658    return ApplicationUsage::NO_HELP;
659}
Note: See TracBrowser for help on using the browser.