Using getopt for required arguments - c

I currently have code that looks like this:
while (( flags = getopt(argc, argv, "abc")) != -1){
switch(flags){
case 'a':
dflag = 1;
break;
case 'b':
rflag = 1;
break;
case 'c':
cflag = 1;
break;
}
}
The problem is I wanted to include something like testprogram -c -d 1
Where c is required to handle the -d, without -c, testprogram -d 1 will just run without arguments.
I tried a large variety of things and I just can't seem to get this to work.
Any help would be appreciated.

I think there are two options available to you, one of which will work and one of which may or may not work.
The 'may or may not work' option would be exemplified by:
char *opts = "abc";
char *opts_d = "abcd:";
while ((opt = getopt(argc, argv, opts)) != -1)
{
switch (opt)
{
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'c':
cflag = 1;
opts = opts_d;
break;
case 'd':
dflag = 1;
dvalue = optarg;
break;
default:
...error handling...
break;
}
}
I'm not sure whether there's anything that prohibits you from changing the list of valid options on successive calls to [getopt()][1], but I do know it is not normally done to change the options as you go. So, treat with caution. Note that if the -c option is never found, the opt value of d will never be returned by getopt(), so that code will not be executed otherwise. Note that if the user enters a -d option before the -c, getopt() will report an invalid option when it processes the -d. You can control the error reporting; you would probably have to. (The optopt variable contains the actual option letter that was encountered as invalid.)
The 'will work' option is:
while ((opt = getopt(argc, argv, "abcd:")) != -1)
{
switch (opt)
{
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'c':
cflag = 1;
break;
case 'd':
if (cflag == 0)
...report error about must use -c option before -d option...
dflag = 1;
dvalue = optarg;
break;
default:
...error handling...
break;
}
}

Related

Using getopt to parse command line options and their arguments

I am trying to use getopt to parse command line options passed by the user of the program. I am specifically struggling with how to save the "option arguments" that are passed with flag, for example like below.
./main -r 213
I am trying to set it up in a way where argument order doesn't matter, and several of my options could pass strings as their argument that I would like to save to a variable. I.e., like below.
./main -o bmp
I have been looking at several resources, but am having trouble even getting the basic ones to print out. For example the code below:
int r, g, b, c;
char t[3];
while ((c = getopt (argc, argv, "abc:")) != -1)
switch (c)
{
case 'r':
printf("Option r has option %s\n", optarg);
break;
case 'g':
printf("Option g has option %s\n", optarg);
break;
case 'b':
printf("Option b has option %s\n", optarg);
break;
break;
case 't':
printf("Option t has option %s\n", optarg);
break;
}
When given this command line argument:
./main -r 123 -g 89 -b -76
Produces this:
./main: invalid option -- 'r'
./main: invalid option -- 'g'
Option b has option (null)
./main: invalid option -- '7'
./main: invalid option -- '6'
Like I mentioned what I actually want to do is store these option arguments off, but I was trying this to understand how they're structured.
Your optstring abc: is incorrect. It should be b:g:r:t: if they all require a value:
#define _POSIX_C_SOURCE 2
#include <stdio.h>
#include <unistd.h>
int main(int argc, char **argv) {
char c;
while ((c = getopt (argc, argv, "b:g:r:t:")) != -1) {
switch (c) {
case 'b':
printf("Option b has option %s\n", optarg);
break;
case 'g':
printf("Option g has option %s\n", optarg);
break;
case 'r':
printf("Option r has option %s\n", optarg);
break;
case 't':
printf("Option t has option %s\n", optarg);
break;
}
}
return 0;
}
and here is the output for your example:
$ ./main -r 123 -g 89 -b -76
Option r has option 123
Option g has option 89
Option b has option -76

Trying to use getopt with a file that begins with a dash '-' as an argument

I am currently working with the function getopt(). I am implementing a program that is similar to the 'ls' command in Unix.
Everything seems to work correctly, however, if say I have a file named "-xyz",and pass the filename as argument, getopt() doesn't treat it as a file/dir.
For example, if i type: ./myprogram -i Makefile -xyz, I expect the function to treat -xyz as a file/dir but instead it tries to treat it as options.
Here is my code:
while((choice = getopt(argc, argv, "ilR")) != -1){
switch(choice) {
case 'i':
opt->option_i = 1;
break;
case 'l':
opt->option_l = 1;
break;
case 'R':
opt->option_R = 1;
break;
default:
exit(1);
}
}
Thank you

Variable Length Argument Parsing with getopt() in C

I am trying to implement a multi layer perceptron library in C and i would like to set the number of hidden layers and the number of perceptrons in each layer from command line with the flag -H where the first number is the number of hidden layers and the following next 2 numbers are the numbers of neurones in that 2 layers respectively, i am using getopt()
For example if i want to create a network with 2 hidden layers each with 5 neurones i will type: -H 2 5 5
for 3 layers with 5, 4 and 3 neurones respectively i will pass -H 3 5 4 3
while ((opt = getopt(argc, argv, ":d:i:o:h:")) != -1) {
switch (opt) {
case 'd':
printf("dataset file: %s\n", optarg);
break;
case 'i':
printf("number of inputs: %s\n", optarg);
break;
case 'h':
// Help need parsing the options here
break;
case 'o':
printf("number of outputs %s\n", optarg);
break;
case '?':
printf("Unknown option: %c\n", optopt);
break;
case ':':
printf("Missing arg for %c\n", optopt);
break;
}
}
As indicated in the comments, the standard convention of 'getopt' is to have one value per option. If you MUST deliver the -h 2 5 4 3 option, consider the following code, which manipulate the optind to skip over the extra values after the '-h'.
int nLayers = 0 ;
int *layers = NULL ;
while ((opt = getopt(argc, argv, ":d:i:o:h:")) != -1) {
switch (opt) {
...
case 'h':
nLayers = atoi(optarg) ;
layers = calloc(nLayers, sizeof(*layers)) ;
for (int i=0 ; i<optarg ; i++ ) {
layers[i] = atoi(argv[optind++]) ;
} ;
// Parse Hidden Layers
break;
...
case ':':
printf("Missing arg for %c\n", optopt);
break;
}
}
Note that the above code does not perform any checks for numeric values.
Also consider '-h 5,4,3' as alternative to '-h 5 -h 4 -h 3' suggestion, using strtok to parse the option values.
int nLayers = 0 ;
int *layers = NULL ;
while ((opt = getopt(argc, argv, ":d:i:o:h:")) != -1) {
switch (opt) {
...
case 'h':
// Parse Hidden Layers
for ( char *p = strtok(optval, ",") ; p != NULL ; p = strtok(NULL, ",") ) {
nLayers++ ;
layers = realloc(layers, sizeof(*layers)*nLayers) ;
layers[nLayers-1] = atoi(p) ;
} ;
break;
...
case ':':
printf("Missing arg for %c\n", optopt);
break;
}
}

I need to get the directory as a command-line argument using getopt in c

I am very new to getopt and I need to get the directory name as an argument by using getopt. It does not work.
The program needs to figure out which argv is the directory so that I can pass the path to a function. I pass either the last command-line argument as a path, if there is a dirname argument, or pass the current working directory to that function.
Please help me on that by providing the correct code fragment:
dt [-h] [-I n] [-L -d -g -i -p -s -t -u | -l] [dirname]
I have tried using optopt but it did not work.
int c;
while( (c = getopt(argc, argv, "hI:Ldgipstul")) != -1){
switch(c){
case 'h':
printf("This is the help message, please read README file for further information");
exit(1);
printf("In the help page\n");
break;
case 'I':
printf("Setting indentation\n");
indentation = atoi(optarg);
printf("Indentation is: %d\n", indentation);
break;
case 'L':
printf("Following symbolic links\n");
break;
case 'd':
//printf("Time of last modification\n");
break;
case 'g':
//printf("Print group id\n");
groupid = groupId(path);
printf("Group Id is: %d\n",groupid);
break;
case 'i':
printf("Print number of links in inode table\n");
int numberlink = numberLinks(path);
printf("number of links: %d\n",numberlink);
break;
case 'p':
printf("Permissions\n");
break;
case 's':
printf("Sizes\n");
break;
case 't':
printf("Information of file\n");
break;
case 'u':
//printf("Print user id\n");
userid = userId(path);
printf("User Id is: %d\n",userid);
break;
case 'l':
printf("Optional one\n");
break;
default:
perror("Not a valid command-line argument");
break;
}
}
When the getopt() loop finishes, the variable optind contains the index of the first non-option argument. That will be the dirname argument. So you can write:
char *directory;
if (optind < argc) {
directory = argv[optind];
} else {
directory = "."; // default to current directory
}

Problems using getopt in C

I wanted to use getopt() to parse arguments supplied at the command line, but I am having trouble with very simple test cases. I have the following code (which is almost, but not entirely identical, to that supplied as an example in the POSIX standard definition).
int main(int argc, char *argv[]) {
int c;
int rmsflg = 0, saflg = 0, errflg = 0;
char *ifile;
char *ofile;
//Parse command line arguments using getopt
while (((c=getopt(argc,argv, ":i:rso:")) != 1) && (errflg == 0)) {
switch(c){
case 'i':
ifile="optarg";
break;
case 'o':
ofile="optarg";
break;
case 'r':
if (saflg)
errflg++;
else {
rmsflg++;
printf("Root Mean Square averaging selected\n");
}
break;
case 's':
if (rmsflg)
errflg++;
else {
saflg++;
printf("Standard Arithmetic averaging selected\n");
}
break;
case ':':
fprintf(stderr,"Option -%c requires an argument\n",optopt);
errflg++;
break;
case '?':
fprintf(stderr,"Option -%c is not a valid option\n",optopt);
errflg++;
break;
default:
fprintf(stderr,"The value of c is %c,\
the option that caused this error is -%c\n",c,optopt);
errflg++;
break;
}
}
if (errflg) {
fprintf(stderr, "usage: xxx\n");
exit(2);
}
return 0;
}
Firstly, when I don't have the default case in there, nothing is output. When I inserted the default case, and make it output the value that c has, I get ?. This is odd for 2 reasons. Firstly, and this is what bothers me most, why doesn't c then match the ? case which was specifically written to match this output, but rather drops through to the default case. Secondly, the output of optopt is (for my input) o. The ? character is only returned if the option supplied does not match any character in optstring.
In the while loop condition you should check the return value of getopt against -1 not 1. Then if you pass the option -? on the command line, it should be recognized.

Resources