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 1251 break;
1252 1252 case detail::Classifer::LONG:
1253 1253 // If already parsed a subcommand, don't accept options_
1254   - _parse_long(args);
  1254 + _parse_arg(args, true);
1255 1255 break;
1256 1256 case detail::Classifer::SHORT:
1257 1257 // If already parsed a subcommand, don't accept options_
1258   - _parse_short(args);
  1258 + _parse_arg(args, false);
1259 1259 break;
1260 1260 case detail::Classifer::NONE:
1261 1261 // Probably a positional or something for a parent (sub)command
... ... @@ -1327,27 +1327,38 @@ class App {
1327 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 1335 std::string current = args.back();
1333 1336  
1334 1337 std::string name;
  1338 + std::string value;
1335 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 1353 // Option not found
1343 1354 if(op_ptr == std::end(options_)) {
1344 1355 // If a subcommand, try the master command
1345 1356 if(parent_ != nullptr && fallthrough_)
1346   - return parent_->_parse_short(args);
  1357 + return parent_->_parse_arg(args, second_dash);
1347 1358 // Otherwise, add to missing
1348 1359 else {
1349 1360 args.pop_back();
1350   - missing_.emplace_back(detail::Classifer::SHORT, current);
  1361 + missing_.emplace_back(current_type, current);
1351 1362 return;
1352 1363 }
1353 1364 }
... ... @@ -1359,7 +1370,13 @@ class App {
1359 1370  
1360 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 1380 op->add_result("");
1364 1381 parse_order_.push_back(op.get());
1365 1382 } else if(!rest.empty()) {
... ... @@ -1392,9 +1409,9 @@ class App {
1392 1409 args.pop_back();
1393 1410 collected++;
1394 1411 }
1395   - //if(collected < -num)
  1412 + // if(collected < -num)
1396 1413 // throw ArgumentMismatch(op->single_name() + ": At least " + std::to_string(-num) + " required");
1397   -
  1414 +
1398 1415 } else {
1399 1416 while(num > 0 && !args.empty()) {
1400 1417 num--;
... ... @@ -1415,85 +1432,6 @@ class App {
1415 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 1437 namespace FailureMessage {
... ... @@ -1519,16 +1457,9 @@ struct AppFriend {
1519 1457  
1520 1458 /// Wrap _parse_short, perfectly forward arguments and return
1521 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 1465 /// Wrap _parse_subcommand, perfectly forward arguments and return
... ...
tests/AppTest.cpp
... ... @@ -248,13 +248,13 @@ TEST_F(TApp, MissingValueMoreThan) {
248 248 std::vector<int> vals2;
249 249 app.add_option("-v", vals1)->expected(-2);
250 250 app.add_option("--vals", vals2)->expected(-2);
251   -
  251 +
252 252 args = {"-v", "2"};
253 253 EXPECT_THROW(run(), CLI::ArgumentMismatch);
254   -
  254 +
255 255 app.reset();
256   -
257   - args = {"--vals","4"};
  256 +
  257 + args = {"--vals", "4"};
258 258 EXPECT_THROW(run(), CLI::ArgumentMismatch);
259 259 }
260 260  
... ... @@ -1173,14 +1173,14 @@ TEST_F(TApp, AllowExtrasOrder) {
1173 1173 TEST_F(TApp, CheckShortFail) {
1174 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 1179 // Test horrible error
1180 1180 TEST_F(TApp, CheckLongFail) {
1181 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 1186 // Test horrible error
... ...