Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: orxonox.OLD/trunk/src/lib/parser/cmdline_parser/cmdline_parser.cc @ 7897

Last change on this file since 7897 was 7319, checked in by bensch, 19 years ago

orxonox/trunk: MUCH more comprehensive SubString

File size: 6.0 KB
Line 
1/*
2   orxonox - the future of 3D-vertical-scrollers
3
4   Copyright (C) 2004 orx
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2, or (at your option)
9   any later version.
10
11   ### File Specific:
12   main-programmer: Christoph Renner
13   co-programmer:
14*/
15
16#include "cmdline_parser.h"
17
18#include "src/lib/util/substring.h"
19
20using namespace std;
21
22
23/**
24 * standard constructor
25 */
26CmdLineParser::CmdLineParser ()
27{
28}
29
30
31/**
32 * standard deconstructor
33 */
34CmdLineParser::~CmdLineParser ()
35{
36}
37
38
39bool CmdLineParser::add( int id, const std::string & longOption, char shortOption, int numArgs, const std::string & argNames, const std::string& help, bool back )
40{
41  ArgTableEntry entry;
42
43  entry.id = id;
44  entry.longOption = longOption;
45  entry.shortOption = shortOption;
46  entry.numArgs = numArgs;
47  entry.argNames = argNames;
48  entry.help = help;
49
50  if ( back )
51    argTable.push_back( entry );
52  else
53    argTable.push_front( entry );
54}
55
56
57bool CmdLineParser::parse( ArgParserCallback cb, void * data, int argc, char ** argv )
58{
59  this->exeName = argv[0];
60
61  //put all args in vector
62  std::vector<std::string> args;
63
64  for ( int i = 1; i<argc; i++ )
65  {
66    std::string s = argv[i];
67
68    if ( s.find( "=" ) == std::string::npos )
69    {
70      if ( s.length() > 2 && s[0] == '-' && s[1] != '-' )
71      {
72        for ( int j = 1; j < s.length(); j++ )
73        {
74          std::string t = "-";
75          t += s[j];
76          args.push_back( t );
77        }
78      }
79      else
80      {
81        args.push_back(s);
82      }
83    }
84    else
85    {
86      std::string op = s;
87      std::string ar = s;
88      op.erase( op.find("=") );
89      ar.erase( 0, ar.find("=")+1);
90
91      //PRINTF(0)("'%s' '%s'\n", op.c_str(), ar.c_str());
92      args.push_back( op );
93      args.push_back( ar );
94    }
95  }
96
97  int i = 0;
98
99  ArgTable::iterator it;
100  bool finish;
101  bool found;
102
103  while ( i < args.size() )
104  {
105    found = false;
106    for ( it = argTable.begin(); it != argTable.end(); it++ )
107    {
108      if ( matches( *it, args[i], finish ) )
109      {
110        found = true;
111
112        int posArgs = 1;
113
114        while ( i + posArgs < args.size() )
115        {
116          if ( args[ i + posArgs ].length() > 0 && args[ i + posArgs ][0] == '-' )
117            break;
118          else
119            posArgs++;
120        }
121
122        posArgs--;
123
124        if ( it->numArgs > posArgs )
125        {
126          PRINTF(1)( "%s needs %d arguments!\n", args[i].c_str(), it->numArgs );
127          return false;
128        }
129
130        std::vector<MultiType> argArgs;
131
132        for ( int j = 1; j <= it->numArgs; j++ )
133          argArgs.push_back( args[i+j] );
134
135        if ( !cb( *it, data, args[i], argArgs ) )
136          return false;
137
138        i += it->numArgs;
139
140        if ( finish )
141        {
142          i++;
143          break;
144        }
145        else
146        {
147          assert( it->numArgs == 0 );
148        }
149      }
150    }
151
152    if ( !found )
153    {
154      PRINTF(1)("%s: illegal option\n", args[i].c_str());
155      return false;
156    }
157  }
158
159  return true;
160}
161
162bool CmdLineParser::matches( ArgTableEntry entry, std::string arg, bool & finish )
163{
164  finish = true;
165
166  if ( arg.length() < 2 )
167    return false;
168
169  if ( arg[0] == '-' )
170  {
171    if ( arg[1] == '-' )
172    {
173      arg.erase( 0, 2 );
174
175      if ( entry.longOption.find('%') != std::string::npos )
176      {
177        //TODO implement bether match algo
178        assert( entry.longOption.find('%') == entry.longOption.length()-1 );
179        std::string lo = entry.longOption;
180        lo.erase( lo.length()-1, 1 );
181        //PRINTF(0)("%s %s\n", arg.c_str(), lo.c_str());
182        return arg.find( lo ) == 0;
183      }
184      else
185      {
186        return arg.find( entry.longOption ) != std::string::npos;
187      }
188    }
189    else
190    {
191      if ( arg.find(entry.shortOption) != std::string::npos && arg.length() != 2 && entry.numArgs != 0 )
192      {
193        PRINTF(1)("using multiple flags together is only alowed if none needs an arugument. %c needs %d arguments\n", entry.shortOption, entry.numArgs);
194        //FIXME find beter solution
195        exit(1);
196        return false;
197      }
198      finish = arg.length()==2;
199      return arg.find(entry.shortOption) != std::string::npos;
200    }
201  }
202  else
203    return false;
204}
205
206void CmdLineParser::showHelp()
207{
208  printf("Usage: %s [options]\n", exeName.c_str());
209  printf("\n");
210
211  std::list<std::vector<std::string> > output;
212
213  for ( ArgTable::iterator it = argTable.begin(); it != argTable.end(); it++ )
214  {
215    output.push_back( std::vector<std::string>() );
216
217    SubString substr( it->argNames );
218    std::string args;
219    assert( it->numArgs == substr.size() );
220
221    for ( int i = 0; i<it->numArgs; i++ )
222    {
223      args += " [" + substr[i] + "]";
224    }
225
226    if ( it->shortOption != '\0' )
227    {
228      output.back().push_back( " -" + std::string((char*)&it->shortOption, 1) );
229      output.back().back() += args;
230    }
231    else
232      output.back().push_back( "" );
233
234    if ( it->longOption != "" )
235    {
236      output.back().push_back( "--" + it->longOption );
237
238      output.back().back() += args;
239    }
240    else
241      output.back().push_back( "" );
242
243    output.back().push_back( it->help );
244  }
245
246  output.push_back( std::vector<std::string>() );
247  output.back().push_back( "Option" );
248  output.back().push_back( "Long option" );
249  output.back().push_back( "Description" );
250
251  output.reverse();
252
253  int maxShort = 0;
254  int maxLong = 0;
255
256  std::list<std::vector<std::string> >::const_iterator it;
257
258  for ( it = output.begin(); it != output.end(); it++ )
259  {
260    if ( (*it)[0].length() > maxShort )
261      maxShort = (*it)[0].length();
262
263    if ( (*it)[1].length() > maxLong )
264      maxLong = (*it)[1].length();
265  }
266
267  for ( it = output.begin(); it != output.end(); it++ )
268  {
269    printf("%s ", (*it)[0].c_str());
270
271    for ( int i = 0; i<maxShort-(*it)[0].length(); i++ )
272      printf(" ");
273
274    printf("%s ", (*it)[1].c_str());
275
276    for ( int i = 0; i<maxLong-(*it)[1].length(); i++ )
277      printf(" ");
278
279    printf("%s\n", (*it)[2].c_str());
280  }
281
282  exit(0);
283}
Note: See TracBrowser for help on using the repository browser.