Using getopt to parse command line options and their arguments - c

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

Related

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.

switch case for parsing options

I am writing a simple program which takes the arguments form the user and process them.
I have the arguments in the argv which is two dimensional array. But when i ran the program, i get the garbage value and the segmentation fault error. I have tried with using argc as terminating condition and it works. But i want to do it using the pointer only.
What am doing wrong with pointer here.
#include<stdio.h>
int main( int argc, char *argv[])
{
while (++(*argv))
{
if ( **argv == '-' )
{
switch (*argv[1])
{
default:
printf("Unknown option -%c\n\n", (*argv)[1]);
break;
case 'h':
printf("\n option h is found");
break;
case 'v':
printf("option V is found");
break;
case 'd':
printf("\n option d is found");
break;
}
}
printf("\n outside while : %s", *argv);
}
}
program run as:
./a.out -h -v -d
Thank you
If you want to iterate through program arguments looking for the terminating null pointer, your outer cycle should be
while (*++argv)
not the
while (++*argv) // <- incorrect!
that you have in your code.
Your switch expression is written incorrectly. While your intent is clear, your implementation ignores operator precedence.
This
switch (*argv[1]) { // <- incorrect!
should actually be
switch ((*argv)[1]) {
The previous if
if (**argv == '-')
is fine, but since it is equivalent to
if ((*argv)[0] == '-') // <- better
maybe you should rewrite it that way as well, just for consistency with switch.
Your ultimate problem is operator precedence. Don't try to be clever when it's unnecessary. The * operator does not work as you think it does. I've rewritten your code using [0] instead, and now it works:
#include <stdio.h>
int main(int argc, char *argv[])
{
while ((++argv)[0])
{
if (argv[0][0] == '-' )
{
switch (argv[0][1]) {
default:
printf("Unknown option -%c\n\n", argv[0][1]);
break;
case 'h':
printf("\n option h is found");
break;
case 'v':
printf("option V is found");
break;
case 'd':
printf("\n option d is found");
break;
}
}
printf("\n outside while : %s", argv[0]);
}
}
argv is an array of strings. argv[0] is the program name which in your case is a.out. Your options start from argv[1]. So you need to iterate argv from 1 to argc-1 to get the options.
Also see here: Parsing Program Arguments

Resources