getopt adding extra functionality in C - c

here is my question. I want to be able to support this in my application:
./cipher [-devh] [-p PASSWD] infile outfile
I managed to get the [-devh] supported, but I don't know how to get [-p PASSWORD] supported. Of course I can manually check for argc being 2 and then have a bunch of flags but I prefer using getopts and think it would be easier. Here is my code for the [-devh] how can I extend it so it can support them remaining?
while ( (c = getopt(argc, argv, "devh")) != -1) {
switch (c) {
case 'd':
printf ("option d\n");
dopt = 1;
break;
case 'e':
printf ("option e\n");
eopt = 1;
break;
case 'v':
printf ("option v\n");
vopt = 1;
break;
case 'h':
printf ("option h\n");
hopt = 1;
break;
default:
printf ("?? getopt returned character code 0%o ??\n", c);
}
}

Taken directly from the GNU C Library Reference page on getopt:
while ((c = getopt (argc, argv, "abc:")) != -1)
switch (c)
{
case 'a':
aflag = 1;
break;
case 'b':
bflag = 1;
break;
case 'c':
cvalue = optarg;
break;
case '?':
if (optopt == 'c')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
return 1;
default:
abort();
}
c here is the argument that takes an optional parameter, so this is probably the syntax you were looking for.
What I understand getopt does is loop through the given arguments, parsing them one at a time. So when it gets to the option c (in your case p) where a second argument is required, it is stored in optarg. This is assigned to a variable of your choice (here cvalue) for later processing.

Related

mandatory and optional options with argc and argv [duplicate]

I have this piece of code in C
while((i = getopt(argc, argv, ":p:h:s:n:l:f:SLNF")) != -1)
switch(i){
case 'p': printf("Porta obbligatoria\n");
break;
case 'h': printf("hostname\n");
break;
case 's': printf("Surname\n");
break;
case 'n': printf("Name\n");
break;
case 'l': printf("Login\n");
break;
case 'f': printf("Faculty\n");
break;
case 'S': printf("Print Surname\n");
break;
case 'L': printf("Print Login\n");
break;
case 'N': printf("Print First name\n");
break;
case 'F': printf("Print Faculty\n");
break;
case '?': printf("USAGE\n");
break;
default: printf("USAGE default\n");
break;
}
return 0;
}
How can I have only one mandatory parameter? In my case is p.
For example:
./MyProgram -p 80 -h 127.0.0.1
Result ok.
./MyProgram -h 127.0.0.1
Error because missing -p
Only -p.
Thanks in advance.
Usually you use the while loop to store the values and then check the mandatory options after the loop:
int p = -1;
while((i = getopt(argc, argv, ":p:h:s:n:l:f:SLNF")) != -1)
switch(i){
case 'p': p = (int)atol(optarg);
break;
<skipped a few options >
default: printf("USAGE default\n");
break;
}
// Check mandatory parameters:
if (p == -1) {
printf("-p is mandatory!\n");
exit 1;
}
return 0;
}

Getopt() Error Checking

I am trying to make it so that getopt can handle certain flags, but I am having trouble implementing the error handling using getopt. I want to prevent duplicate flags such as '-s 1 -s 1', and having too many arguments for a flag '-s 1 2' both of these should exit the program.
int opt; //command flags
while((opt = getopt(argc, argv, "s:f:")) != -1){
switch(opt){
case 's':
printf("%s\n", optarg);
printf("%i\n", optind);
break;
case 'f':
printf("%s\n", optarg);
printf("%i\n", optind);
break;
default:
//unknown command flags
fprintf(stderr, "Usage: fred [ -s symbol-table-file ] [ -f fred-program-file ]\n");
return EXIT_FAILURE;
}
}
Too many arguments (e.g., program -s f1 -f f2 hello). Duplicate flags (e.g., program -s f1 -s f2). Both should exit the program
For each option, you may maintain a flag to see if the option has already been encountered or not. Duplicate options are detected with the help of these flags.
int c, sflag=0, fflag=0;
while( (c=getopt(argc, argv, "s:f:"))!=-1 )
{
switch(c)
{
case 's':
if(sflag!=0)
{
//fprintf(stderr, "\n dup s option");
return 1; //duplicate s option
}
sflag++;
//printf("\ns flag: %s", optarg);
break;
case 'f':
if(fflag!=0)
{
//fprintf(stderr, "\n dup f option");
return 1; //duplicate f option
}
fflag++;
//printf("\nf flag: %s", optarg);
break;
case '?':
if(isprint(optopt))
{
fprintf(stderr, "Unknown option %c", optopt);
}
else
{
fprintf(stderr, "\nUnknown option character x%x", optopt);
}
return 1;
}
}
optind will have the index of the next argv[] which is still to be examined. After all the options have been taken care of, in your program there should be exactly one non-option argument.
So, optind must be equal to argc-1 for a correct usage of the command.
if(optind != argc-1) //exactly one non-option argument is expected
{
fprintf(stderr, "\nInvalid number of arguments.");
return 1;
}

Optopt and getopt in C

I'm trying to figure out getopt, but I keep getting hung up at the end of the switch statement.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main (int argc, char **argv)
{
int aflag = 0;
int bflag = 0;
char *filename = NULL, *x = NULL;
int index;
int c;
opterr = 0;
while ((c = getopt (argc, argv, "hnc:")) != -1)
switch (c)
{
case 'h':
printf("You chose h");
break;
case 'n':
x = optarg;
break;
case 'l':
filename = optarg;
break;
case '?':
if (optopt == 'n' || optopt == 'l')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr,
"Unknown option character `\\x%x'.\n",
optopt);
return 1;
default:
abort ();
}
for (index = optind; index < argc; index++)
printf ("Non-option argument %s\n", argv[index]);
return 0;
}
When I compile this and run a.out -l it does as it should, but when I do a.out -n it does nothing, when it should say "Option n requires an argument."
How can I fix this?
Your optstring "hnc:" says n is a valid argument that doesn't require an argument, while l is not specified at all so the ? case will always be hit. Try using
getopt (argc, argv, "hn:l:")
which says n and l both require arguments.

C: getopt(): option does not seem to have effect

I am trying out the following C code (saved in file called testgetopt.c):
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
#include <ctype.h>
void usage(char *s)
{
fprintf(stderr, "Usage: %s [-d] -i input-TIFF-file -o output-raw-file\n", s);
fprintf(stderr, "Note: -d indicates debugging option\n");
}
int main(int argc, char **argv) {
char c;
size_t i;
char *itext = NULL, *otext = NULL;
FILE *fout;
short debug = 0;
if ((c = getopt(argc, argv, "di:o:")) == EOF) {
usage(argv[0]);
exit(1);
}
while ((c = getopt(argc, argv, "di:o:")) != EOF) {
switch (c) {
case 'd':
debug = 1;
break;
case 'i':
itext = optarg;
break;
case 'o':
otext = optarg;
break;
case '?':
if (optopt == 'i' || optopt == 'o')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
usage(argv[0]);
exit(1);
default:
fprintf(stderr, "Both -i and -o are needed\n");
usage(argv[0]);
exit(1);
}
}
printf("debug = %i\n", debug);
if (debug)
printf ("input file = %s, output file = %s\n", itext, otext);
return EXIT_SUCCESS;
}
I compile using:
gcc testgetopt.c
But regardless of whether I include -d or not, I always get debug set at 0. The program should have -d set debug at 1, 0 otherwise.
What is being done wrong?
Here are the examples:
Let us first try with no -d
./a.out -i in.dat -o out.dat
debug = 0
Let us next try with -d included.
./a.out -d -i in.dat -o out.dat
debug = 0
Thank you in advance for any help and suggestions!
The problem is that you are calling getopt as a sanity check and then not using its result when it succeeds. That means the first option is always discarded. You can easily verify this by putting -d as a non-first option:
$ ./a.out -i in.dat -o out.dat -d
debug = 1
input file = (null), output file = out.dat
You can see that the -d did take effect this time but the first argument, -i, is not set.
There are several ways to fix this. The recommended way (IMHO) is to remove the first getopt call. Then change the sanity check to verify the actual options. That is, there should be code after the getopt loop which verifies that all mandatory options have been provided.
For example:
int main(int argc, char **argv) {
char c;
size_t i;
char *itext = NULL, *otext = NULL;
FILE *fout;
short debug = 0;
/* REMOVED THIS BLOCK OF CODE
if ((c = getopt(argc, argv, "di:o:")) == EOF) {
usage(argv[0]);
exit(1);
}
*/
while ((c = getopt(argc, argv, "di:o:")) != EOF) {
switch (c) {
case 'd':
debug = 1;
break;
case 'i':
itext = optarg;
break;
case 'o':
otext = optarg;
break;
case '?':
if (optopt == 'i' || optopt == 'o')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
else if (isprint (optopt))
fprintf (stderr, "Unknown option `-%c'.\n", optopt);
else
fprintf (stderr, "Unknown option character `\\x%x'.\n", optopt);
usage(argv[0]);
exit(1);
default:
fprintf(stderr, "Both -i and -o are needed\n");
usage(argv[0]);
exit(1);
}
}
/* ADD SOME ARGUMENT SANITY CHECKS */
if (!itext || !otext) {
printf("Missing mandatory arguments\n");
exit(1);
}
printf("debug = %i\n", debug);
if (debug)
printf ("input file = %s, output file = %s\n", itext, otext);
return EXIT_SUCCESS;
}
Because you are calling getopt twice, you need to reset optind = 1; between the calls.

Function getopt in C

I have a problem with situation when I don't write parameters, which I would like to be essential.
while ((choice = getopt(argc, argv, "a:b:")) != -1) {
switch (choice) {
case 'a' :
printf("a %s\n", optarg);
break;
case 'b' :
printf("b %d\n", optarg);
break;
case '?' :
if (optopt == 'a')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
break;
}
}
When I write ./a.out -b test I don't see fprintf() message
I think you'll need to track whether or not option -a has been used yourself - getopt() doesn't have a rich enough spec to capture that information. Something like:
int opt_a_found = 0;
while ((choice = getopt(argc, argv, "a:b:")) != -1) {
switch (choice) {
case 'a' :
opt_a_found = 1;
printf("a %s\n", optarg);
break;
case 'b' :
printf("b %d\n", optarg);
break;
case '?' :
if (optopt == 'a')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
break;
}
}
if (!opt_a_found) {
fprintf (stderr, "Option -a is required.\n");
}
Assuming you mean printf() when wrting fprintf():
I might be wrong, but as far as I remember optarg is char * so you should use %s also in your second printf().
In case you really meant fprintf() please explain why you expect to see it.
because your fprintf is under this condition if (optopt == 'a') which will be false when optopt is 'b'
if (optopt == 'a')
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
break;
try
if (optopt == 'a' || optopt == 'b' )
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
break;

Resources