Some command line switches stand alone. Others are followed by options, such as a starting value, filename, and other settings. The getopt() function processes these values along with the switches, providing you know the secret.
Before revealing the secret (you can wait), know that a switch-case structure nested in a while loop is the best way to process multiple switches. The following listing shows how such a beast is assembled:
2021_07_17-Lesson-a.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int r;
/* suppress getopt()'s error message */
opterr = 0;
while( (r=getopt(argc,argv,"az")) != -1 )
{
switch(r)
{
case 'a':
puts("-a option is activated");
/* do A option stuff here */
break;
case 'z':
puts("-z option is activated");
/* do Z option stuff here */
break;
case '?':
printf("'%c' is an invalid argument\n",optopt);
break;
default:
puts("Unknown argument");
}
}
return(0);
}
The program accepts two arguments, -a and -z, as shown at Line 12. They can be specified in any order, as shown by these sample runs:
$ ./a.out -a -z
-a option is activated
-z option is activated
$ ./a.out -z -a
-z option is activated
-a option is activated
You can even bunch them up:
$ ./a.out -az
-a option is activated
-z option is activated
$ ./a.out -za
-z option is activated
-a option is activated
Things get tricky for the getopt() function when a switch requires an option. (This is the secret part.) For example:
$ ./a.out -a 177
Above, the -a switch requires an option, say the number of people who fully understand double pointers in C. To notify the getopt() function of such an option, suffix a colon to the switch’s character in the option string:
getopt(argc,argv,"a:z")
Above, the -a switch has an option but -z does not. The option is available immediately after the getopt() function reads the -a. It’s accessed as a string through the optarg global variable. So, when the option is a numeric value, you must convert it from a string to the proper data type.
The following code processes an argument for the -a switch, but not the -z switch:
2021_07_17-Lesson-b.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int r;
/* suppress getopt()'s error message */
opterr = 0;
while( (r=getopt(argc,argv,"a:z")) != -1 )
{
switch(r)
{
case 'a':
/* -a has an argument */
printf("-a option with argument %s\n",optarg);
/* do A option stuff here */
break;
case 'z':
puts("-z option is activated");
/* do Z option stuff here */
break;
case '?':
printf("'%c' is an invalid argument\n",optopt);
break;
default:
puts("Unknown argument");
}
}
return(0);
}
In the case statements for option -a (starting at Line 16), the optarg variable is used in the printf() statement to output whatever argument follows -a. As with sample output shown previously, you can specify -a and -z in any order, but -a must have an argument, otherwise the optarg variable is misread. For example:
$ ./a.out -a -z
-a option with argument -z
It’s up to your code to determine whether the proper argument is set — or even available. Otherwise the switches are misinterpreted and their purpose is lost.
For multiple arguments with options, set a colon after each one in the getopt() function’s argument string. This operation can be tricky: You must test for each switch’s options. Otherwise a missing argument throws off the entire process.
In next week’s Lesson, I cover the getopt_long() function, which processes full-word switches prefixed by a double-dash.