Universal solution
The simplest way around the problem presented is:
n = atoi(argv[1]);
argv[1] = argv[0];
++argv;
--argc;
while ((opt = getopt(argc, argv, "hi:o:")) != -1)
{
...as before...
}
This effectively consumes the first option and then rejigs things to the orthodox format. This works with any version of getopt()
that is remotely compliant with the standards (de facto and de jure). Note that if you don't reassign argv[1] = argv[0];
, getopt()
will use the value in the original argv[1]
(the number in this example) as the 'name of the program'.
Using GNU getopt()
With GNU getopt()
, there are two ways to handle the problem. One uses the 'return in order' feature so that non-option ('file name') arguments are treated as if they were prefixed by an option character code 1 (ASCII SOH control character; aka Control-A). The other uses the default mode whereby getopt()
permutes the options as it processes them. Note that this is not available by default on Mac OS X, amongst other platforms.
This code almost does both jobs; you simply have to change the option string between the 'permute' mode (shown) and the 'return in order' mode using "-hi:o:"
.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <getopt.h>
int main(int argc, char **argv)
{
int n;
int opt;
char *ifile = 0;
char *ofile = 0;
n = atoi(argv[1]);
while ((opt = getopt(argc, argv, "hi:o:")) != -1)
{
printf("Option: %c\n", opt);
switch (opt)
{
case 'i':
ifile = optarg;
break;
case 'o':
ofile = optarg;
break;
case 'h':
printf("...");
break;
case 1:
n = atoi(optarg);
break;
default:
printf("Invalid Option %d\n", opt);
exit(1);
}
}
printf("argc = %d; optind = %d\n", argc, optind);
for (int i = optind; i < argc; i++)
printf("argv[%d] = %s\n", i, argv[i]);
if (ifile != 0)
printf("i-file: %s\n", ifile);
if (ofile != 0)
printf("o-file: %s\n", ofile);
printf("%d\n", n);
return 0;
}
Example run with 'permute':
$ go9 9 -i in -o out
Option: i
Option: o
argc = 6; optind = 5
argv[5] = 9
i-file: in
o-file: out
9
$
Example run with 'return in order':
$ go9 9 -i in -o out
Option:
Option: i
Option: o
argc = 6; optind = 6
i-file: in
o-file: out
9
$
Make sure you do not have environment variable POSIXLY_CORRECT set if you want this to work. You can prefix the option string with a +
to force POSIX-like behaviour.