void CmdlineParser::parse()

in src/controller/cmdline_parser.h [153:246]


void CmdlineParser<CLI>::parse(int argc, char** argv)
{
    // generate input data for getopt_long()
    option long_opts[CLI::num + 1]; // +1 for NULL-option
    char   short_opts[CLI::num * 2 + 2] = {0};

    short_opts[0] = ':';

    char* short_p = &short_opts[1];
    for(int i = 0; i < CLI::num; ++i)
    {
        const Opt& a = CLI::options[i];

        long_opts[i].name    = a.long_opt;
        long_opts[i].has_arg = (a.type == Opt::Type::NOA) ? no_argument : required_argument;
        long_opts[i].flag    = 0;
        long_opts[i].val     = 0;

        if(a.short_opt)
        {
            *short_p = a.short_opt;
            ++short_p;
            if(a.type != Opt::Type::NOA)
            {
                *short_p = ':'; // argument to option is required
                ++short_p;
            }
        }
    }

    // fill last element
    memset(&long_opts[CLI::num], 0, sizeof(long_opts[CLI::num]));

    // assuming that argc and argv are the same as those passed to program
    int opt_index = 0;

    while(true)
    {
        int opt = getopt_long(argc, argv, short_opts, long_opts, &opt_index);
        if(opt == -1)
        {
            break;
        }

        switch(opt)
        {
        case 0:
            // store long option
            set_value(opt_index, optarg);
            break;

        case '?':
        {
            std::string unkn{build_name(optopt, argv[optind - 1])};
            throw CLIError{std::string{"Unrecognized option: "} + unkn};
        }

        case ':':
        {
            std::string miss{build_name(optopt, argv[optind - 1])};
            throw CLIError{std::string{"Option requires an argument: "} + miss};
        }

        default:
        {
            // if short option found
            const int index = short_opt_index(opt);
            if(index != -1)
            {
                set_value(index, optarg);
            }
        }
        }
    }

    // if we get non-option element in args, throw exception
    if(optind != argc)
    {
        // quote non-option
        std::string name{build_name(0, argv[optind])};
        throw CLIError{std::string{"Unexpected operand on command line: "} + name};
    }

    // set default values
    for(Opt& o : CLI::options)
    {
        if(o.value == nullptr     // is value still uninitialized?
           && o.deflt != nullptr) // try to substitute by default value
        {
            o.value  = o.deflt;
            o.passed = false;
        }
    }
}