| 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 |  | 
|---|
| 20 | using namespace std; | 
|---|
| 21 |  | 
|---|
| 22 |  | 
|---|
| 23 | /** | 
|---|
| 24 |  * standard constructor | 
|---|
| 25 |  */ | 
|---|
| 26 | CmdLineParser::CmdLineParser () | 
|---|
| 27 | { | 
|---|
| 28 | } | 
|---|
| 29 |  | 
|---|
| 30 |  | 
|---|
| 31 | /** | 
|---|
| 32 |  * standard deconstructor | 
|---|
| 33 |  */ | 
|---|
| 34 | CmdLineParser::~CmdLineParser () | 
|---|
| 35 | { | 
|---|
| 36 | } | 
|---|
| 37 |  | 
|---|
| 38 |  | 
|---|
| 39 | bool 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 |  | 
|---|
| 57 | bool 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 |  | 
|---|
| 162 | bool 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 |  | 
|---|
| 206 | void 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 | } | 
|---|