0

I am using the command line options for the type of operation so, for say a Login, user has to execute command like NameOfExe --username Admin --password Admin

My question is how can i make sure that user enters proper values to the optiopns he provided and thorw err in a case like this NameOfExe --username --password ?

EDIT:-

For now I take the argument values like this

char* Cli::getCmdOption(char** begin,
                    char** end,
                    const std::string& option)
{
  char** itr = std::find(begin, end, option);

  if (itr != end && ++itr != end)
  {
        return *itr;
  }
    return (char*)"";
}

And used it as getCmdOption(argv , argv+argc , "--userName")

DevMac
  • 131
  • 1
  • 2
  • 9
  • usually you can make such decisions using your `main`'s `argc` `argv` – pergy Mar 14 '17 at 07:58
  • Boost has an excellent interface for command line argument parsing. Use that? See http://stackoverflow.com/questions/253556/what-parameter-parser-libraries-are-there-for-c – Bathsheba Mar 14 '17 at 07:58
  • In the example you show, its simply to check if there is a username provided but no password. – Some programmer dude Mar 14 '17 at 07:59
  • I do have command line params i.e argc,argv but there are multiple command expecting different parametes like --name and --proxy – DevMac Mar 14 '17 at 08:02
  • All the more reason for using the Boost parser. Did you check the link? – Bathsheba Mar 14 '17 at 08:04
  • Can you please refer the link @Bathsheba – DevMac Mar 14 '17 at 08:16
  • 1
    See http://www.boost.org/doc/libs/1_36_0/doc/html/program_options.html It's a bit of a learning curve (if you've never used Boost before then allow a month), but worth it in my opinion. And your market value goes up if you have Boost experience. – Bathsheba Mar 14 '17 at 08:16
  • @DevMac, you really should show us how you're parsing arguments at the moment; I'm guessing a simple loop with an `if`/`else` cascade? Seeing your structure would really help people to give an *appropriate* answer; you should be able to write a small program as a [mcve], then we can advise how to add the checking you want. Note that in this case (`NameOfExe --username --password`) it might be impossible, *unless you can determine that `--password` can't be a valid user name* (or that `--password` is a required argument). It's different from `--username ''`, which is more easily tested. – Toby Speight Mar 14 '17 at 08:59
  • I have multiple activities eg Login, Logout and Several Other commands for eg: Login, there are mandatory parameters associated with it that if user has given I take it buy parsing it, and if there is any one parameter missing from mandatory param list, I thorw error. – DevMac Mar 14 '17 at 09:10
  • If else loop is not possible as there are different param list of mandatory and optional param list for different activities @TobySpeight – DevMac Mar 14 '17 at 09:11
  • Hope the EDIT makes things more lucid. @TobySpeight – DevMac Mar 14 '17 at 09:18
  • Yes it does - and it's a surprise, because I've never seen argument parsing done that way before. – Toby Speight Mar 14 '17 at 09:24
  • `return (char*)"";` is going to give you gyp: pointer to an anonymous temporary. **don't do that!!** Use `nullptr` instead. – Bathsheba Mar 14 '17 at 09:24

1 Answers1

0

That's a very unusual way to do argument parsing, and it may cause problems when the parameter to an argument is also a valid option itself (such as in your --loginname "--password" example.

A more idiomatic C++ approach (either directly in your code, or buried in an option-parsing library) iterates over argv[], considering each word in turn:

#include <iostream>
#include <string>
#include <vector>

int main(int argc, char **argv)
{
    std::string username;
    std::string password;
    std::vector<std::string> values;

    for (auto i = 1;  i < argc;  ++i) {
        std::string arg = argv[i];
        if (arg == "--username") {
            ++i;
            if (i >= argc) {
                std::cerr << argv[0] << ": --username requires a value" << std::endl;
                return 1;
            }
            username = argv[i];
        } else if (arg == "--password") {
            ++i;
            if (i >= argc) {
                std::cerr << argv[0] << ": --password requires a value" << std::endl;
                return 1;
            }
            password = argv[i];
        } else {
            values.emplace_back(argv[i]);
        }
    }


    std::cout << "Username = " << username << '\n';
    std::cout << "Password = " << password << '\n';
    for (auto i = 0u;  i < values.size();  ++i)
        std::cout << "Argument " << i << " = " << values[i] << '\n';
}

Obviously there's a lot of duplication above, but the principle applies: test each argument in turn, and if it's an option that requires a value, advance the argument index and read that value.

Once you get past a small number of options, you'll end up creating a mapping from option name to a representation of how to process that option, and either use or re-invent an option processing library.

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
  • 1
    Using a `std::string` for a password ain't particularly secure, although this can help: http://stackoverflow.com/questions/3785582/how-to-write-a-password-safe-class – Bathsheba Mar 14 '17 at 09:46
  • That's not what I expect, I have mentioned that there are n numbers of parameters and not only --userName and --password so this is not a generic solution. @Toby Speight – DevMac Mar 14 '17 at 09:49
  • Like I said, when you have more parameters, you tend more to a table-based solution, but *the principle is unchanged* whether you have a cascaded `if`/`else` chain or a table. Read each argument in turn, and if it needs one or more options then read those. Do you want help, or merely spoon-feeding? – Toby Speight Mar 14 '17 at 09:58
  • Note also that as the number of possible options increases, so does the cost of searching for each in the argument list. A table-based iteration over the arguments is linear in the number of arguments, whereas searching is proportional to the product of the argument count and the number of options available. – Toby Speight Mar 14 '17 at 09:59
  • I think you did not get the question. The solution you gave is fine and can be done using table, but since each Operation involves different parameters it is not possible to keep a common table for the application. – DevMac Mar 14 '17 at 11:14
  • Parsers such as [`tclap`](http://tclap.sourceforge.net/manual.html) manage it, so you should be able to. It can be as simple as a `std::map>` that you populate with function objects that act on `argc` and `argv` and fill in your program's `options` structure, all the way up to a generic library such as the one I linked. – Toby Speight Mar 14 '17 at 13:11