How to use getopt_long to parse multiple arguments?

#include <iostream> #include <getopt.h> #define no_argument 0 #define required_argument 1 #define optional_argument 2 int main(int argc, char * argv[]) { std::cout << "Hello" << std::endl; const struct option longopts[] = { {"version", no_argument, 0, 'v'}, {"help", no_argument, 0, 'h'}, {"stuff", required_argument, 0, 's'}, {0,0,0,0}, }; int index; int iarg=0; //turn off getopt error message opterr=1; while(iarg != -1) { iarg = getopt_long(argc, argv, "s:vh", longopts, &index); switch (iarg) { case 'h': std::cout << "You hit help" << std::endl; break; case 'v': std::cout << "You hit version" << std::endl; break; case 's': std::cout << "You hit stuff" << std::endl; if(optarg) std::cout << "Your argument(s): " << optarg << std::endl; break; } } std::cout << "GoodBye!" << std::endl; return 0; } 

Desired conclusion:

 ./a.out --stuff someArg1 someArg2 Hello You hit stuff Your agument(s): someArg1 someArg2 GoodBye! 
+4
source share
3 answers

getopt returns -1 when all argument arguments are processed. --stuff recognized as an option that takes an argument, in this case someArg1 . The someArg2 argument someArg2 not start with - or -- so this is not an option. By default, this will be moved to the end of argv . After getopt returns -1, all arguments without options will be in argv from optind to argc-1 :

 while (iarg != -1) { iarg = getopt_long(argc, argv, "s:vh", longopts, &index); // ... } for (int i = optind; i < argc; i++) { cout << "non-option arg: " << argv[i] << std::endl; } 

If you add one to the beginning of optstring , getopt will return 1 (not '1') and the optarg item to the parameter without the option:

 while (iarg != -1) { iarg = getopt_long(argc, argv, "-s:vh", longopts, &index); switch (iarg) { // ... case 1: std::cout << "You hit a non-option arg:" << optarg << std::endl; break; } } 
+7
source

In the line ./a.out --stuff someArg1 someArg2 shell interprets three arguments for a.out. You want the shell to interpret "someArg1 someArg2" as a single argument - so put the words in quotation marks:

 ./a.out --stuff "someArg1 someArg2" 
+2
source

I am working on windows, so I had to compile getopt and getopt_long from this excellent source

I modified getopt_long.c (below) to accommodate two input arguments. I was not worried about a more general case with several arguments, as this would require more (and cleaner) refinement than I had the time / need. The second argument is placed in another global "optarg2".

If you don't need to compile getopt from the source code, Frank's answer above looks more elegant.

 extern char * optarg2 . . . int getopt_long(nargc, nargv, options, long_options, index) { . . . if (long_options[match].has_arg == required_argument || long_options[match].has_arg == optional_argument || long_options[match].has_arg == two_req_arguments) { if (has_equal) optarg = has_equal; else optarg = nargv[optind++]; if (long_options[match].has_arg == two_req_arguments) { optarg2 = nargv[optind++]; } } if ((long_options[match].has_arg == required_argument || long_options[match].has_arg == two_req_arguments) && (optarg == NULL)) { /* * Missing argument, leading : * indicates no error should be generated */ if ((opterr) && (*options != ':')) (void)fprintf(stderr, "%s: option requires an argument -- %s\n", __progname(nargv[0]), current_argv); return (BADARG); } if ((long_options[match].has_arg == two_req_arguments) && (optarg2 == NULL)) { /* * Missing 2nd argument, leading : * indicates no error should be generated */ if ((opterr) && (*options != ':')) (void)fprintf(stderr, "%s: option requires 2nd argument -- %s\n", __progname(nargv[0]), current_argv); return (BADARG); } 

You also need to add a definition to getopt.h for "two_required_args" or "multiple_args" as you see fit.

edit: I'm bad at markdown

0
source

Source: https://habr.com/ru/post/1390300/


All Articles