Using getopt in C with non-option arguments
According to https://www.man7.org/linux/man-pages/man3/getopt.3.html
By default, getopt() permutes the contents of argv as it scans, so that eventually all the nonoptions are at the end. Two other scanning modes are also implemented. If the first character of optstring is '+' or the environment variable POSIXLY_CORRECT is set, then option processing stops as soon as a nonoption argument is encountered. If the first character of optstring is '-', then each nonoption argv-element is handled as if it were the argument of an option with character code 1. (This is used by programs that were written to expect options and other argv-elements in any order and that care about the ordering of the two.) The special argument "--" forces an end of option-scanning regardless of the scanning mode.
int main(int argc, char** argv) {
char* inputfile;
char* outputfile;
char* output_file_type;
char* color_red;
char* color_blue;
char* color_green;
int opt;
if (argv[optind] == NULL || argv[optind + 1] == NULL) {
printf("Mandatory argument(s) missing\n");
exit(1);
}
while((opt = getopt(argc, argv, ":i:o:r:g:b:t:")) != -1){
switch(opt){
case 'i':
inputfile = optarg;
printf("Input file : %s\n",inputfile);
break;
case 'o':
outputfile = optarg;
printf("Output File: %s\n",outputfile);
break;
case 't':
output_file_type = optarg;
printf("Output File type: %s\n", output_file_type);
break;
case 'r':
color_red = optarg;
printf("Color Red: %s\n",color_red);
break;
case 'g':
color_green = optarg;
printf("Color Green: %s\n",color_green);
break;
case 'b':
color_blue = optarg;
printf("Color Blue: %s\n",color_blue);
break;
case ':':
printf("option needs a value\n");
break;
case '?':
printf("unknown option: %c\n", optopt);
break;
}
}
for (; optind < argc; optind++){
printf("Given extra arguments: %s\n", argv[optind]);
}
return (EXIT_SUCCESS);
}
Run commands:
gcc main.c -o image
./image -i ./resource/input_file.bmp -o ./resource/output_file.bmp -t BPM -r 10 -g 24 -b 40
output:
Input file : ./resource/input_file.bmp
Output File: ./resource/output_file.bmp
Output File type: BPM
Color Red: 10
Color Green: 24
getopt
sets the optind
variable to indicate the position of the next argument.
Add code similar to this after the options loop:
if (argv[optind] == NULL || argv[optind + 1] == NULL) {
printf("Mandatory argument(s) missing\n");
exit(1);
}
Edit:
If you want to allow options after regular arguments you can do something similar to this:
while (optind < argc) {
if ((c = getopt(argc, argv, "i:d:btw:h:s:")) != -1) {
// Option argument
switch (c) {
case 'i': {
i = (int)atol(optarg);
}
case 'd': {
d = (int)atol(optarg);
}
case 'b':
buf = 1;
break;
case 't':
time = 1;
break;
case 'w':
w = (int)atol(optarg);
break;
case 'h':
h = (int)atol(optarg);
break;
case 's':
s = (int)atol(optarg);
break;
default:
break;
}
else {
// Regular argument
<code to handle the argument>
optind++; // Skip to the next argument
}
}
Really good example could be found here: GNU Libc The code:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main (int argc, char **argv)
{
int aflag = 0;
int bflag = 0;
char *cvalue = NULL;
int index;
int c;
opterr = 0;
while ((c = getopt (argc, argv, "abc:")) != -1)
switch (c)
{
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'c':
cvalue = optarg;
break;
case '?':
if (optopt == 'c')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
default:
abort ();
}
printf ("aflag = %d, bflag = %d, cvalue = %s\n",
aflag, bflag, cvalue);
for (index = optind; index < argc; index++)
printf ("Non-option argument %s\n", argv[index]);
return 0;
}
It allows to have options before and after arguments. I did compile and run test example:
$ ./a.out aa ff bb -a -ctestparam hello
aflag = 1, bflag = 0, cvalue = testparam
Non-option argument aa
Non-option argument ff
Non-option argument bb
Non-option argument hello