Commit 1b3a4b63c894682bb991480991dfce5e495f538a

Authored by Henry Fredrick Schreiner
Committed by Henry Schreiner
1 parent 133c7d50

Combining parse functions for short and long

include/CLI/App.hpp
@@ -1251,11 +1251,11 @@ class App { @@ -1251,11 +1251,11 @@ class App {
1251 break; 1251 break;
1252 case detail::Classifer::LONG: 1252 case detail::Classifer::LONG:
1253 // If already parsed a subcommand, don't accept options_ 1253 // If already parsed a subcommand, don't accept options_
1254 - _parse_long(args); 1254 + _parse_arg(args, true);
1255 break; 1255 break;
1256 case detail::Classifer::SHORT: 1256 case detail::Classifer::SHORT:
1257 // If already parsed a subcommand, don't accept options_ 1257 // If already parsed a subcommand, don't accept options_
1258 - _parse_short(args); 1258 + _parse_arg(args, false);
1259 break; 1259 break;
1260 case detail::Classifer::NONE: 1260 case detail::Classifer::NONE:
1261 // Probably a positional or something for a parent (sub)command 1261 // Probably a positional or something for a parent (sub)command
@@ -1327,27 +1327,38 @@ class App { @@ -1327,27 +1327,38 @@ class App {
1327 throw HorribleError("Subcommand " + args.back() + " missing"); 1327 throw HorribleError("Subcommand " + args.back() + " missing");
1328 } 1328 }
1329 1329
1330 - /// Parse a short argument, must be at the top of the list  
1331 - void _parse_short(std::vector<std::string> &args) { 1330 + /// Parse a short (false) or long (true) argument, must be at the top of the list
  1331 + void _parse_arg(std::vector<std::string> &args, bool second_dash) {
  1332 +
  1333 + detail::Classifer current_type = second_dash ? detail::Classifer::LONG : detail::Classifer::SHORT;
  1334 +
1332 std::string current = args.back(); 1335 std::string current = args.back();
1333 1336
1334 std::string name; 1337 std::string name;
  1338 + std::string value;
1335 std::string rest; 1339 std::string rest;
1336 - if(!detail::split_short(current, name, rest))  
1337 - throw HorribleError("Short parsed but missing! You should not see this");  
1338 1340
1339 - auto op_ptr = std::find_if(  
1340 - std::begin(options_), std::end(options_), [name](const Option_p &opt) { return opt->check_sname(name); }); 1341 + if(second_dash) {
  1342 + if(!detail::split_long(current, name, value))
  1343 + throw HorribleError("Long parsed but missing (you should not see this):" + args.back());
  1344 + } else {
  1345 + if(!detail::split_short(current, name, rest))
  1346 + throw HorribleError("Short parsed but missing! You should not see this");
  1347 + }
  1348 +
  1349 + auto op_ptr = std::find_if(std::begin(options_), std::end(options_), [name, second_dash](const Option_p &opt) {
  1350 + return second_dash ? opt->check_lname(name) : opt->check_sname(name);
  1351 + });
1341 1352
1342 // Option not found 1353 // Option not found
1343 if(op_ptr == std::end(options_)) { 1354 if(op_ptr == std::end(options_)) {
1344 // If a subcommand, try the master command 1355 // If a subcommand, try the master command
1345 if(parent_ != nullptr && fallthrough_) 1356 if(parent_ != nullptr && fallthrough_)
1346 - return parent_->_parse_short(args); 1357 + return parent_->_parse_arg(args, second_dash);
1347 // Otherwise, add to missing 1358 // Otherwise, add to missing
1348 else { 1359 else {
1349 args.pop_back(); 1360 args.pop_back();
1350 - missing_.emplace_back(detail::Classifer::SHORT, current); 1361 + missing_.emplace_back(current_type, current);
1351 return; 1362 return;
1352 } 1363 }
1353 } 1364 }
@@ -1359,7 +1370,13 @@ class App { @@ -1359,7 +1370,13 @@ class App {
1359 1370
1360 int num = op->get_expected(); 1371 int num = op->get_expected();
1361 1372
1362 - if(num == 0) { 1373 + /// ONE ///////////////////////////////////////////////////////////////
  1374 + if(!value.empty()) {
  1375 + if(num != -1)
  1376 + num--;
  1377 + op->add_result(value);
  1378 + parse_order_.push_back(op.get());
  1379 + } else if(num == 0) {
1363 op->add_result(""); 1380 op->add_result("");
1364 parse_order_.push_back(op.get()); 1381 parse_order_.push_back(op.get());
1365 } else if(!rest.empty()) { 1382 } else if(!rest.empty()) {
@@ -1392,9 +1409,9 @@ class App { @@ -1392,9 +1409,9 @@ class App {
1392 args.pop_back(); 1409 args.pop_back();
1393 collected++; 1410 collected++;
1394 } 1411 }
1395 - //if(collected < -num) 1412 + // if(collected < -num)
1396 // throw ArgumentMismatch(op->single_name() + ": At least " + std::to_string(-num) + " required"); 1413 // throw ArgumentMismatch(op->single_name() + ": At least " + std::to_string(-num) + " required");
1397 - 1414 +
1398 } else { 1415 } else {
1399 while(num > 0 && !args.empty()) { 1416 while(num > 0 && !args.empty()) {
1400 num--; 1417 num--;
@@ -1415,85 +1432,6 @@ class App { @@ -1415,85 +1432,6 @@ class App {
1415 args.push_back(rest); 1432 args.push_back(rest);
1416 } 1433 }
1417 } 1434 }
1418 -  
1419 - /// Parse a long argument, must be at the top of the list  
1420 - void _parse_long(std::vector<std::string> &args) {  
1421 - std::string current = args.back();  
1422 -  
1423 - std::string name;  
1424 - std::string value;  
1425 - if(!detail::split_long(current, name, value))  
1426 - throw HorribleError("Long parsed but missing (you should not see this):" + args.back());  
1427 -  
1428 - auto op_ptr = std::find_if(  
1429 - std::begin(options_), std::end(options_), [name](const Option_p &v) { return v->check_lname(name); });  
1430 -  
1431 - // Option not found  
1432 - if(op_ptr == std::end(options_)) {  
1433 - // If a subcommand, try the master command  
1434 - if(parent_ != nullptr && fallthrough_)  
1435 - return parent_->_parse_long(args);  
1436 - // Otherwise, add to missing  
1437 - else {  
1438 - args.pop_back();  
1439 - missing_.emplace_back(detail::Classifer::LONG, current);  
1440 - return;  
1441 - }  
1442 - }  
1443 -  
1444 - args.pop_back();  
1445 -  
1446 - // Get a reference to the pointer to make syntax bearable  
1447 - Option_p &op = *op_ptr;  
1448 -  
1449 - int num = op->get_expected();  
1450 -  
1451 - if(!value.empty()) {  
1452 - if(num != -1)  
1453 - num--;  
1454 - op->add_result(value);  
1455 - parse_order_.push_back(op.get());  
1456 - } else if(num == 0) {  
1457 - op->add_result("");  
1458 - parse_order_.push_back(op.get());  
1459 - } else if(num < 0) {  
1460 - // Unlimited vector parser  
1461 - int collected = 0; // Make sure we always eat the minimum  
1462 - while(!args.empty() && _recognize(args.back()) == detail::Classifer::NONE) {  
1463 - if(collected >= -num) {  
1464 - // We could break here for allow extras, but we don't  
1465 -  
1466 - // If any positionals remain, don't keep eating  
1467 - if(_count_remaining_positionals() > 0)  
1468 - break;  
1469 -  
1470 - // If there are any unlimited positionals, those also take priority  
1471 - if(std::any_of(std::begin(options_), std::end(options_), [](const Option_p &opt) {  
1472 - return opt->get_positional() && opt->get_expected() < 0;  
1473 - }))  
1474 - break;  
1475 - }  
1476 - op->add_result(args.back());  
1477 - parse_order_.push_back(op.get());  
1478 - args.pop_back();  
1479 - collected++;  
1480 - }  
1481 - //if(collected < -num)  
1482 - // throw ArgumentMismatch(op->single_name() + ": At least " + std::to_string(-num) + " required");  
1483 - } else {  
1484 - while(num > 0 && !args.empty()) {  
1485 - num--;  
1486 - op->add_result(args.back());  
1487 - parse_order_.push_back(op.get());  
1488 - args.pop_back();  
1489 - }  
1490 - if(num > 0) {  
1491 - throw ArgumentMismatch(op->single_name() + ": " + std::to_string(num) + " required " +  
1492 - op->get_type_name() + " missing");  
1493 - }  
1494 - }  
1495 - return;  
1496 - }  
1497 }; 1435 };
1498 1436
1499 namespace FailureMessage { 1437 namespace FailureMessage {
@@ -1519,16 +1457,9 @@ struct AppFriend { @@ -1519,16 +1457,9 @@ struct AppFriend {
1519 1457
1520 /// Wrap _parse_short, perfectly forward arguments and return 1458 /// Wrap _parse_short, perfectly forward arguments and return
1521 template <typename... Args> 1459 template <typename... Args>
1522 - static auto parse_short(App *app, Args &&... args) ->  
1523 - typename std::result_of<decltype (&App::_parse_short)(App, Args...)>::type {  
1524 - return app->_parse_short(std::forward<Args>(args)...);  
1525 - }  
1526 -  
1527 - /// Wrap _parse_long, perfectly forward arguments and return  
1528 - template <typename... Args>  
1529 - static auto parse_long(App *app, Args &&... args) ->  
1530 - typename std::result_of<decltype (&App::_parse_long)(App, Args...)>::type {  
1531 - return app->_parse_long(std::forward<Args>(args)...); 1460 + static auto parse_arg(App *app, Args &&... args) ->
  1461 + typename std::result_of<decltype (&App::_parse_arg)(App, Args...)>::type {
  1462 + return app->_parse_arg(std::forward<Args>(args)...);
1532 } 1463 }
1533 1464
1534 /// Wrap _parse_subcommand, perfectly forward arguments and return 1465 /// Wrap _parse_subcommand, perfectly forward arguments and return
tests/AppTest.cpp
@@ -248,13 +248,13 @@ TEST_F(TApp, MissingValueMoreThan) { @@ -248,13 +248,13 @@ TEST_F(TApp, MissingValueMoreThan) {
248 std::vector<int> vals2; 248 std::vector<int> vals2;
249 app.add_option("-v", vals1)->expected(-2); 249 app.add_option("-v", vals1)->expected(-2);
250 app.add_option("--vals", vals2)->expected(-2); 250 app.add_option("--vals", vals2)->expected(-2);
251 - 251 +
252 args = {"-v", "2"}; 252 args = {"-v", "2"};
253 EXPECT_THROW(run(), CLI::ArgumentMismatch); 253 EXPECT_THROW(run(), CLI::ArgumentMismatch);
254 - 254 +
255 app.reset(); 255 app.reset();
256 -  
257 - args = {"--vals","4"}; 256 +
  257 + args = {"--vals", "4"};
258 EXPECT_THROW(run(), CLI::ArgumentMismatch); 258 EXPECT_THROW(run(), CLI::ArgumentMismatch);
259 } 259 }
260 260
@@ -1173,14 +1173,14 @@ TEST_F(TApp, AllowExtrasOrder) { @@ -1173,14 +1173,14 @@ TEST_F(TApp, AllowExtrasOrder) {
1173 TEST_F(TApp, CheckShortFail) { 1173 TEST_F(TApp, CheckShortFail) {
1174 args = {"--two"}; 1174 args = {"--two"};
1175 1175
1176 - EXPECT_THROW(CLI::detail::AppFriend::parse_short(&app, args), CLI::HorribleError); 1176 + EXPECT_THROW(CLI::detail::AppFriend::parse_arg(&app, args, false), CLI::HorribleError);
1177 } 1177 }
1178 1178
1179 // Test horrible error 1179 // Test horrible error
1180 TEST_F(TApp, CheckLongFail) { 1180 TEST_F(TApp, CheckLongFail) {
1181 args = {"-t"}; 1181 args = {"-t"};
1182 1182
1183 - EXPECT_THROW(CLI::detail::AppFriend::parse_long(&app, args), CLI::HorribleError); 1183 + EXPECT_THROW(CLI::detail::AppFriend::parse_arg(&app, args, true), CLI::HorribleError);
1184 } 1184 }
1185 1185
1186 // Test horrible error 1186 // Test horrible error