Wrong output when printing one of the elements in argv - c

I am writing a program that recurses through directories but came across a strange problem with my code. I compile and run the code with the following:
./sorter -c food -d thisdir -o thatdir
The following gives me a total argument count of 7. However when I try to check my inputs, I get unexpected results:
int main(int argc, char ** argv){
int checkInputs = checkFlags(argc,argv);
if(checkInputs == 1){
fileSearch(".");
}
else if(checkInputs == 2){
printf("arg counts %d\n",argc);
printf("%s\n",argv[4]);
fileSearch(argv[4]);
}
else if(checkInputs == 3){
printf("arg counts %d\n",argc);
printf("%s\n",argv[4]);
fileSearch(argv[4]);
}
return 0;
}
It returns the expected output when checkInputs is 2 but when it is 3 I get the following when I print argv[4]:
-d
The following is my checkInputs function, which may be causing this:
int checkFlags(int argc, char * argv[]) {
int output;
if(argc < 3){
printf("Not enough arguments\n");
output = 0;
return output;
}
else{
int options;
char * input = NULL;
while((options = getopt(argc,argv,"c:d::o::")) != -1){
switch(options) {
case 'c':
input = optarg;
//printf("Mandatory flag: %s\n",optarg);
output = 1;
break;
case 'd':
//printf("We have an optional %s\n",argv[4]);
output = 2;
break;
case 'o':
//printf("We have two optionals: -d: %s & -o: %s\n",argv[4],argv[6]);
output = 3;
break;
/* Probably don't need this case statement*/
case '?':
if(optopt == 'c'){
printf("Unknown option, -%c not present\n",optopt);
exit(0);
}
break;
}
}
}
return output;
}
Everything works fine however if the program is only compiled with the first 2 flags.

By debugging your code, I actually get a segmentation fault, when checkInputs == 2 and ./program -c hello -d. You should fix this, by adding a IF and check if a path is provided, for the option -d. Also keep in mind, that the sequence of the parameters can differ. You can save the extra options in a variable to access them out of the checkFlags function.
Executing ./program -c food -d thisdir -o thatdir outputs:
Mandatory flag: food
We have an optional thisdir
We have two optionals: -d: thisdir & -o: thatdir
arg counts 7
-o
It prints the expected.

Related

Cant seem to access multiple options using getopt() for C [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
TL;DR - My issue is that I can't seem to get both options to work. Only '-n' is working. I also want '-h' to work.
I am trying to create a program that essentially prints out the last few letters of '.txt' or '.log' file. However, I am running into an issue using getopt(). I am trying to access the different cases using the command line, but I can only access the first case
I have already tried include the colon (:) after "nLh" however it ends up outputting a "segmentation fault" (core dumped)" error.
Ex1: ./print.out -h (fails)
What I pass in
./print.out -h
Expected output
Usage: ./print.out -n
Actual output
Segmentation fault (core dump)
Ex2: ./print.out -n 60 (Successful)
What I pass in
./print.out -n 60
Expected output
Random text file from a txt file ... Random text file from a txt file
Actual output
Random text file from a txt file ... Random text file from a txt file
if(argc >1)
{
while ((option =getopt(argc,argv,"nLh"))!=-1)
{
switch (option)
{
case 'n':
if( isExtensionTXTorLog && charactersRead >0)
{
}
else if( argc == 3 && !isExtensionTXTorLog)
{
}
else
{
exit(2);
}
break;
case 'L':
break;
case 'h':
printUsage();
break;
case '?':
exit(0);
break;
default:
break;
}
}
}
else
{
accessDefault(buffer);
return 0;
}
You're using optind in the wrong way. optind is used to get non-options argument after parsing all the options. To parse option with argument use n:, then read optarg variable
Take look at this minimal example:
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[])
{
char option;
int n_param;
while ((option =getopt(argc,argv,"n:h"))!=-1)
{
//Variable initialization
switch (option)
{
case 'n':
n_param = atoi(optarg);
printf("Param N: %d\n", n_param);
break;
case 'h':
printf("Help\n");
exit(0);
break;
case '?':
printf("Unrecognized option\n");
exit(0);
break;
default:
break;
}
}
for (int index = optind; index < argc; index++)
printf ("Non-option argument %s\n", argv[index]);
return 0;
}
Example:
./a.out ARG1 -n 50 ARG2
Output:
Param N: 50
Non-option argument ARG1
Non-option argument ARG2

Multiple integer arguments with getopt?

What is the best way to handle multiple integer arguments while using getopt? I have to be able to enter something like this on the command line: calc -a 100 50 and it will add up 100 and 50.
while ((opt = getopt(argc, argv, "adms")) != -1)
{
value = atoi(argv[optind + 1]);
printf("value : %d\n", value);
switch (opt)
{
case 'a': aFlag = 1; num1 = atoi(argv[optind]);
sum = num1 + value;
printf("%d + %d = %d\n" , num1, value, sum);
break;
case 'd': dFlag = 1;
break;
case 'm': break;
case 's': break;
default:
fprintf(stderr, "%s: unknown option %c\n", argv[0], optopt);
return 1;
}
}
if (aFlag == 1)
{
num1 = atoi(argv[optind]);
sum = num1 + value;
printf("%d + %d = %d\n" , num1, value, sum);
}
if (dFlag == 1)
{
num2 = atoi(argv[optind]);
sub = num2 / value;
printf("%d / %d = %d\n" , num2, value, sum);
}
I think that the interface you're after is probably:
./program -a 100 50
which accepts a single option -a (alternatives -m, -s and -d), and then processes the other arguments as a list of numbers, rather than as values attached to the option. This works fine unless you planned to be able to use:
./program -a 100 50 -m 20 30
to do addition and multiplication.
What do you want to do if someone can't make their mind up and tries:
./program -am 100 50
Should it be an error, or should -a or -m win? You can argue for any of those with some degree of coherency. I'd go with an error, though.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static int op_add(int a, int b) { return a + b; }
static int op_sub(int a, int b) { return a - b; }
static int op_mul(int a, int b) { return a * b; }
static int op_div(int a, int b) { return a / b; }
int main(int argc, char **argv)
{
int (*fun)(int, int) = 0;
char op;
int opt;
while ((opt = getopt(argc, argv, "adms")) != -1)
{
if (fun != 0)
{
fprintf(stderr, "%s: you can't use two operations\n", argv[0]);
return 1;
}
switch (opt)
{
case 'a': fun = op_add; op = '+'; break;
case 'd': fun = op_div; op = '/'; break;
case 'm': fun = op_mul; op = '*'; break;
case 's': fun = op_sub; op = '-'; break;
default:
fprintf(stderr, "%s: unknown option %c\n", argv[0], optopt);
return 1;
}
}
if (fun == 0 || optind + 2 != argc)
{
fprintf(stderr, "Usage: %s [-adms] num1 num2\n", argv[0]);
return 1;
}
int res = fun(atoi(argv[optind]), atoi(argv[optind+1]));
printf("%s %c %s = %d\n", argv[optind], op, argv[optind+1], res);
return 0;
}
The error checking on the values in the 'numeric' arguments is reprehensibly sloppy (meaning, non-existent). There's no division by zero check, either. But that at least produces plausible answers. It would probably be better to have an array of structures saving the function pointer and the operation character, but that sort of refinement is for you to deal with.
If you need a negative number, use -- to mark the end of the options:
$ ./program -m -- -39 -75
-39 * -75 = 2925
$
Just in case you're not sure about it, int (*fun)(int, int) is a pointer to a function that takes two int arguments and returns an int result. It allows the code to select which function to execute at runtime.
With getopt(), an option can take at most one argument. If you want your program to handle its command line with getopt(), and it must accept arguments such as you describe
calc -a 100 50
, and you must not repeat options, then the only viable solution is to make one or both of the integers non-option arguments instead of arguments to the -a option. I'd suggest making both (or all) non-option arguments. Thus, you might have something like this:
int result = getopt(argc, argv, "asmd");
switch (result) {
case 'a':
// careful: getopt() will be confused by negative numbers
if (getopt(argc, argv, "asmd") != -1) {
fprintf(stderr, "usage: %s -a|-s|-m|-d <operands>\n", argv[0]);
exit(1);
}
do_add(argv + optind);
break;
case 's':
// ...
}
After getopt() returns -1, optind is the index in argv one past that of the last option (+/- option argument) processed.
This excerpt from the man page for getopt() clearly shows that each of the answers (and the original question) are not showing an understanding of getopt:
optstring is a string containing the legitimate option characters.
If such a character is followed by a colon,
[then] the option requires an argument,
so getopt() places a pointer
to the following text in the same argv-element,
or the text of the following argv-element,
in optarg.
your code should also allow for the following:
If getopt() does not recognize an option character,
it prints an error message to stderr,
stores the character in optopt,
and returns '?'.
and finally this (which will allow for the - to be in any position on the command line:
By default, getopt() permutes the contents of argv as it scans, so that
eventually all the nonoptions are at the end.

Issue with options order in getopt

I am having trouble with getopt. In my program, I wish to run the program with the following options: -l -w -n -b. n and b are optional, however the program must have either l or w, not both. Also, if w is invoked, it must be followed by an argument. Also, the order should be l or w first, followed by n or b, whose order does not matter.
Here are examples of valid arguments:
./prog -l -n -b
./prog -w argument -b -n
./prog -l -n
./prog -l -b
These examples are not valid:
./prog -l -w argument
./prog -n -l
./prog -b -l
Based on these requirements, I having having trouble using getopt. Of course I can use a myriad of if else statements, but that would be ugly and unnecessarily complicated.
Specifically, I am having trouble with the order of the arguments and making -l and -w options an either or relationship.
Here is what I have so far, although it is not much because of these uncertainties.
while ((option = getopt(argc, argv,"lw:nb:")) != -1) {
switch(option) {
case'l': ... // I haven't wrote anything here yet
case'w': ...
case'n': ...
case'b': ...
case '?': ...
default: ...
}
}
First, getopt makes sure that w has an argument. That's the point of the
: in your getopt string. If -b does not need an argument, then you should remove the : after it.
Second, I don't think verifying argument conditions is as bad as you're thinking
it's going to be. You should already have variables to keep track of your
options, like this:
int opt_l = 0;
int opt_w = 0;
char *arg_w = 0;
int opt_n = 0;
int opt_b = 0;
You should also have a function that prints out the usage and a helpful error
message to the user, like this:
int exit_usage(const char *err)
{
if( err ) { printf("Bad arguments: %s\n", err); }
printf("Usage: ...\n");
exit(1);
}
Then it's a simple one-line check to verify your preconditions. If a
precondition fails, then print an error and show the usage info to your user.
You don't have to cram the precondition check into one line, but it tends to
be easier to read a list of preconditions when they're all one line each.
Like this:
while ((option = getopt(argc, argv, "lw:nb")) != -1)
{
switch(option)
{
case 'l':
if( opt_w != 0 ) { exit_usage("Cannot combine -l with -w"); }
++opt_l;
break;
case 'w':
if( opt_l != 0 ) { exit_usage("Cannot combine -l with -w"); }
arg_w = optarg;
++opt_w;
break;
case 'n':
if( opt_l == 0 && opt_w == 0 ) { exit_usage("-n requires -l or -w first"); }
++opt_n;
break;
case 'b':
if( opt_l == 0 && opt_w == 0 ) { exit_usage("-n requires -l or -w first"); }
++opt_b;
break;
case '?':
exit_usage(NULL);
break;
default:
break;
}
}

Passing few arguments via getopt

What I want to do is to get more arguments from the command line and get them output each one on a new line. How could I do that by keeping the same structure? I want also to get the -f output.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
int
main(int argc, char *argv[])
{
int nod1, opt;
int nsecs, nod2;
nsecs = 0;
nod2 = 0;
nod1 = 0;
while ((opt = getopt(argc, argv, "nf:")) != -1) {
switch (opt) {
case 'n':
nod1 = 1;
break;
case 'f':
nsecs = atoi(optarg);
nod2 = 1;
break;
default: /* '?' */
fprintf(stderr, "Usage: %s [-t nsecs] [-n] name\n",
argv[0]);
exit(EXIT_FAILURE);
}
}
printf("nod1=%d; nod2=%d; optind=%d\n", nod1, nod2, optind);
if (optind >= argc) {
fprintf(stderr, "Expected argument after options\n");
exit(EXIT_FAILURE);
}
printf("Output = %s\n", argv[optind]);
/* Other code omitted */
exit(EXIT_SUCCESS);
}
From a comment:
The arguments after the -f should be optional and I want to list every single one that has been passed under one another...
$ ./partitioner -n 4 -f Test1 Test2 Test3 Test4
Number:4
File names:
Output = Test1
Output = Test2
Output = Test3
Output = Test4
$
Having in account the comment made by Jonathan Leffler I edit my answer:
POSIX getopt() doesn't really handle optional arguments sensibly. GNU getopt() is a bit better, but not by much. Avoid them whenever you can.
I come out with a simple idea, but one that could solve your problem so here it is:
In argv you have a list of arguments ordered as they was in the commend line right? So, if you can find any -f in argv that means all arguments following -f until another option or the end of the argument list are the options you want to print.
From -f to another option(-g in this case):
./command -a A -b B -f one two tree -g G
From -f to the end.
./command -a A -b B -f one two tree
Here you have a helper function for doing that:
bool get_f_args(int argc, char *argv[], int &count, int* indexes)
{
bool f_found = false, parsing_f_args = false;
int collect_count = 0;
if (argc < 3) return false; // "./command -f" are just two values for argv
// we need at least 3.
// Check for every argument in the argument list.
for (int i = 1; i < argc; i++)
{
// If you found another option
// stop collecting args.
if (argv[i][0] == '-' && parsing_f_args) // options starts with '-' character.
parsing_f_args = false;
if (parsing_f_args)
indexes[count++] = i;
// If some is "-f" then the following are the
// ones you're looking for. We check for -f after
//
// indexes[count++] = i;
//
// in roder to avoid adding -f index to indexes.
if (strcmp("-f", argv[i]) == 0) {
parsing_f_args = true;
f_found = true;
}
}
return f_found;
}
And here is an example of use:
int main(int argc, char* argv[])
{
int count = 0;
int indexes[10];
bool f_found = get_f_args(argc, argv, count, indexes);
if (f_found){
for (int i = 0; i < count; i++)
printf("Ouput = %s\n", argv[indexes[i]]);
}
return 0;
}

C getopt does not read all the parameters

I have an assignment in C that requires options to be read in for different forms of a program. Before I start on that, though, I want to make sure that the getopt portion is working fine. However, the program keeps dropping the last parameter and I don't know why. Whenever I enter the last char, the program goes to the default value that kills the program. Any help is appreciated!
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
int main(int argc, char **argv)
{
int sFlag = 0;
int lFlag = 0;
int dFlag = 0;
int rFlag = 0;
int c;
opterr = 0;
while ((c = getopt (argc, argv, "slr:")) != -1)
{
switch(c)
{
case 's':
sFlag = 1;
break;
case 'l':
lFlag = 1;
break;
case 'r':
rFlag = 1;
break;
default:
printf("unknown parameter introduced");
exit(-1);
break;
}
}
printf("s = %i, l = %i, d = %i, r = %i", sFlag, lFlag, dFlag, rFlag);
return 1;
}
The colon symbol after r in "slr:" tells getopt() to wait for a mandatory argument which follows -r.
Examples:
getopt(argc, argv, "slr:") can parse ./project -s -l -r r_arg (or ./project -r r_arg -s etc.)
getopt(argc, argv, "s:lr:") can parse ./project -s s_arg -l -r r_arg
getopt(argc, argv, "s:lr:") can also parse ./project -s -l -r r_arg with no error, but the program works differently from user's expectation. This is because getopt() expects -s to be followed by its argument, however it looks like, so the next argument -l is consumed and will not hit your switch(c).

Resources