Reputation: 55
I would like to implement a copy of the Linux head commmand. If the user types in ./cprogram head -(option here)
I would like for the option to appear but for some reason my code never enters the options switch
statement. For example the command line code ./cprogram head -n
never enters the case 'n':
statement. The code was working before the if
statement to check if the argv[1]
is "head"
.
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv) {
int b;
int c;
int nflag = 0;
int Vflag = 0;
int hflag = 0;
int eflag = 0;
int oflag = 0;
char str[] = "head";
if (strcmp(argv[1], str) == 0) {
while ((c = getopt(argc, argv, "nVheo")) != -1) {
switch (c) {
case 'n':
if (nflag||Vflag||hflag||eflag||oflag) {
printf("only one option\n");
exit(1);
} else {
nflag++;
printf("n option\n");
}
break;
case 'V':
if (nflag||Vflag||hflag||eflag||oflag) {
printf("only one option\n");
exit(1);
} else {
Vflag++;
}
break;
case 'h':
if (nflag||Vflag||hflag||eflag||oflag) {
printf("only one option\n");
exit(1);
} else {
hflag++;
}
break;
case 'e':
if (nflag||Vflag||hflag||eflag||oflag) {
printf("only one option\n");
exit(1);
} else {
eflag++;
}
break;
case 'o':
if (nflag||Vflag||hflag||eflag||oflag) {
printf("only one option\n");
exit(1);
} else {
oflag++;
}
break;
default:
printf("invalid options\n");
abort();
}
}
} else {
}
}
I would greatly appreciate an expert eye to have a look and spot what I'm missing. Thanks in advance.
Upvotes: 3
Views: 749
Reputation: 144780
For getopt()
to skip argv[1]
and parse options from the next element, you should set optind
before calling getopt()
:
optind = 2;
Also note that you should also check if argc > 1
before comparing argv[1]
with "head"
.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char **argv) {
int b;
int c;
int nflag = 0;
int Vflag = 0;
int hflag = 0;
int eflag = 0;
int oflag = 0;
char str[] = "head";
if (argc > 1 && strcmp(argv[1], str) == 0) {
optind = 2; // skip argv[1]
while ((c = getopt(argc, argv, "nVheo")) != -1) {
if (nflag | Vflag | hflag | eflag | oflag) {
fprintf(stderr, "only one option\n");
exit(1);
}
switch (c) {
case 'n':
nflag++;
printf("n option\n");
break;
case 'V':
Vflag++;
break;
case 'h':
hflag++;
break;
case 'e':
eflag++;
break;
case 'o':
oflag++;
break;
default:
fprintf(stderr, "invalid option `%c'\n", c);
abort();
}
}
/* perform head on files starting at argv[optind] */
} else {
/* test some other command */
}
}
Upvotes: 2
Reputation: 33601
Combining all the suggestions in the top comments:
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char **argv)
{
int b;
int c;
int nflag = 0;
int Vflag = 0;
int hflag = 0;
int eflag = 0;
int oflag = 0;
char str[] = "head";
if (argc < 2) {
printf("not enough arguments\n");
exit(1);
}
if (strcmp(argv[1], str) != 0) {
printf("1st argument is not '%s'\n",str);
exit(1);
}
// skip over the [matched] str
--argc;
++argv;
while ((c = getopt(argc, argv, "nVheo")) != -1) {
if (nflag || Vflag || hflag || eflag || oflag) {
printf("only one option\n");
exit(1);
}
switch (c) {
case 'n':
nflag++;
printf("n option\n");
break;
case 'V':
Vflag++;
break;
case 'h':
hflag++;
break;
case 'e':
eflag++;
break;
case 'o':
oflag++;
break;
default:
printf("invalid options\n");
abort();
break;
}
}
return 0;
}
To test, invoke with these [a shell script test
]:
./myprogram
./myprogram foo
./myprogram head
./myprogram head -n
./myprogram head -n -n
Here is the sh -x ./test
output:
+ ./myprogram
not enough arguments
+ ./myprogram foo
1st argument is not 'head'
+ ./myprogram head
+ ./myprogram head -n
n option
+ ./myprogram head -n -n
n option
only one option
UPDATE:
The above code is a bit of a "cheat". It eliminates the str
(e.g. "head"
) by moving it into argv[0]
which is the program name (e.g. ./myprogram
). The actual program name gets trashed.
A more correct way is to "slide" argv
to eliminate the string and preserve the program name:
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main(int argc, char **argv)
{
int b;
int c;
int nflag = 0;
int Vflag = 0;
int hflag = 0;
int eflag = 0;
int oflag = 0;
char str[] = "head";
if (argc < 2) {
printf("not enough arguments\n");
exit(1);
}
if (strcmp(argv[1], str) != 0) {
printf("1st argument is not '%s'\n",str);
exit(1);
}
// skip over the [matched] str
for (int avidx = 1; avidx < argc; ++avidx)
argv[avidx] = argv[avidx + 1];
--argc;
while ((c = getopt(argc, argv, "nVheo")) != -1) {
if (nflag || Vflag || hflag || eflag || oflag) {
printf("only one option\n");
exit(1);
}
switch (c) {
case 'n':
nflag++;
printf("n option\n");
break;
case 'V':
Vflag++;
break;
case 'h':
hflag++;
break;
case 'e':
eflag++;
break;
case 'o':
oflag++;
break;
default:
printf("invalid options\n");
abort();
break;
}
}
return 0;
}
Upvotes: 2