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

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

Removed the redundent prepending of application name.

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