getopt is not working for one of my parameters - c

I have to programm a TCP/UDP Server/Client software.
Possible arguments: -u: UDP -t: TCP -l Server -p: [Port] -h [IP]
I wrote a function printflags, to see if everything works fine.
The u-, t-, l- and p-Options work fine. But my IP is everytime NULL.
Where is the problem?
#include <ctype.h>
#include <stdio.h>
#include <getopt.h>
#include <stdlib.h>
#include <unistd.h>
int printflags(int, int, int, char *,char *);
int main(int argc, char *argv[]){
int uflag=0;
int tflag=0;
int lflag=0;
char *pvalue = NULL;
char *hvalue = NULL;
int c;
opterr = 0;
while((c = getopt (argc, argv, "utlhp:")) != -1)
{
switch(c)
{
case 'u':
uflag = 1;
break;
case 't':
tflag = 1;
break;
case 'l':
lflag = 1;
break;
case 'p':
pvalue = optarg;
break;
case 'h':
hvalue = optarg;
break;
case ':':
fprintf(stderr, "case :");
case '?':
if(optopt == 'p' || optopt == 'h')
fprintf(stderr, "Option '-%c' requires an argument.\n", optopt);
else if (isprint(optopt))
fprintf(stderr, "Unknown option character '-%c'.\n", optopt);
else
fprintf(stderr, "Unknown option character '%x'.\n", optopt);
return 1;
default:
abort();
}
}
printflags(uflag, tflag, lflag, pvalue, hvalue);
return 0;
}
int printflags(int uflag, int tflag, int lflag, char* pv, char *hv){
printf("-u UDP: %d\n", uflag);
printf("-t TCP: %d\n", tflag);
printf("-l Listen Socket - Server: %d\n", lflag);
printf("-p Port: %s\n", pv);
printf("-h IP: %s\n", hv);
return 0;
}

Your option string should be "utlh:p:". You need a colon after each letter that takes an optarg.

Your parameter to getopt() needs a colon after the h to signify that -h needs an argument.
while((c = getopt (argc, argv, "utlh:p:")) != -1)
// ^ --- here

Related

C program help to open a file in Unix/Linux using getopt and command line argument

I am trying to work on my college assignment that required programming in C in Unix. I have to take command line arguments and open a file with the name passed as an argument. I've been trying to find help, but couldn't find any resources to help me understand how to parse the argument as a string and open the required file. I'm seeking examples or links that point me in the right direction.
I'm including the short piece of code where I'm trying to parse the options using getopt(). What am I doing wrong?
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main(int argc[], char *argv[])
{
int option;
while(option = getopt(argc, argv, "hi:o:") != -1)
{
switch (option){
case 'h':
printf("Usage : -i [input file name]\n-o [output file name]");
break;
case 'i':
printf("\n Input file is: %s",argv[1]);
break;
case 'o':
printf("\n Output file is: %s",argv[2]);
break;
}
}
return 0;
}
I keep getting "Unrecognized command line option error". Also, when I try to include a text file, I believe that the error says that the option is being parsed as an int, but the argument is a string.
P.S: I'm not really looking get any direct answers here. I want the community to help me learn in the best possible way.
As mentioned in the comments, you should be using optarg. Here is an example that is pretty comprehensive:
/*
example of command line parsing via getopt
usage: getopt [-dmp] -f fname [-s sname] name [name ...]
Paul Krzyzanowski
*/
#include <stdio.h>
#include <stdlib.h>
int debug = 0;
int
main(int argc, char **argv)
{
extern char *optarg;
extern int optind;
int c, err = 0;
int mflag=0, pflag=0, fflag=0;
char *sname = "default_sname", *fname;
static char usage[] = "usage: %s [-dmp] -f fname [-s sname] name [name ...]\n";
while ((c = getopt(argc, argv, "df:mps:")) != -1)
switch (c) {
case 'd':
debug = 1;
break;
case 'm':
mflag = 1;
break;
case 'p':
pflag = 1;
break;
case 'f':
fflag = 1;
fname = optarg;
break;
case 's':
sname = optarg;
break;
case '?':
err = 1;
break;
}
if (fflag == 0) { /* -f was mandatory */
fprintf(stderr, "%s: missing -f option\n", argv[0]);
fprintf(stderr, usage, argv[0]);
exit(1);
} else if ((optind+1) > argc) {
/* need at least one argument (change +1 to +2 for two, etc. as needeed) */
printf("optind = %d, argc=%d\n", optind, argc);
fprintf(stderr, "%s: missing name\n", argv[0]);
fprintf(stderr, usage, argv[0]);
exit(1);
} else if (err) {
fprintf(stderr, usage, argv[0]);
exit(1);
}
/* see what we have */
printf("debug = %d\n", debug);
printf("pflag = %d\n", pflag);
printf("mflag = %d\n", mflag);
printf("fname = \"%s\"\n", fname);
printf("sname = \"%s\"\n", sname);
if (optind < argc) /* these are the arguments after the command-line options */
for (; optind < argc; optind++)
printf("argument: \"%s\"\n", argv[optind]);
else {
printf("no arguments left to process\n");
}
exit(0);
}
This example and more information is found here.

opterr declaration in getopt

The following is example code from http://www.gnu.org. As surely most of you will see, it's getopt and I am having a question about the variable declarations. Why is there no type or anything written in front of
opterr = 0;
I have never seen that before.
#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 *cvalue = NULL;
int index;
int c;
opterr = 0;
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 ();
}
printf ("aflag = %d, bflag = %d, cvalue = %s\n",
aflag, bflag, cvalue);
for (index = optind; index < argc; index++)
printf ("Non-option argument %s\n", argv[index]);
return 0;
}
opterr(3) is declared as an extern variable in unistd.h:
extern int optind, opterr, optopt;
So it's a global variable defined in a different translation unit, in this case your standard C library.
The reason for setting it to 0 is also explained in the manpage:
If getopt() does not recognize an option character, it prints an error message to stderr, stores the character in optopt, and returns '?'. The calling program may prevent the error message by setting opterr to 0.

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 programming with getopt(): giving command line flags criteria

I am beginning to teach myself C. I have run into a few bumps here and there but right now I am stumped by getOpt(). The main thing thats giving me trouble is when I try to make certain flags dependent on other flags. For example I want these to work:
./myfile -a -b -c blue
But none of the other options to work without -a. Thus ./myfile -b -c purple would be invalid. Is it possible for getopt to handle this kind of "flag dependent" criteria? How would I go about doing that? Secondly, lets say that no matter which flags are passed, along with it must be a colour.
So ./myfile -a -b green and ./myfile red are both valid. I understand that this all lies within the options parameter of getOpt() (which is currently set up to look something like this "abc"), but how would I make one parameter required for each instance without doing "a:b:c:" since this would not include the mandatory colour if no flags are passed.
Here's the example (from the manpage) of getopt:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int
main (int argc, char *argv[])
{
int flags, opt;
int nsecs, tfnd;
nsecs = 0;
tfnd = 0;
flags = 0;
while ((opt = getopt (argc, argv, "nt:")) != -1)
{
switch (opt)
{
case 'n':
flags = 1;
break;
case 't':
nsecs = atoi (optarg);
tfnd = 1;
break;
default: /* '?' */
fprintf (stderr, "Usage: %s [-t nsecs] [-n] name\n", argv[0]);
exit (EXIT_FAILURE);
}
}
printf ("flags=%d; tfnd=%d; optind=%d\n", flags, tfnd, optind);
if (optind >= argc)
{
fprintf (stderr, "Expected argument after options\n");
exit (EXIT_FAILURE);
}
printf ("name argument = %s\n", argv[optind]);
/* Other code omitted */
exit (EXIT_SUCCESS);
}
Note you'll need to add some declarations, and a main() function to get that to work.
You can see the example n above is a flag, and works like your b option. The t option above takes a parameter and works like your c option. If you want to have an a option that is also a flag, you would make the getopt parameter "abf:" (i.e. add an a in without a colon), and a stanza to the switch like this:
case 'a':
aflag = 1;
break;
having first set aflag to 0. At the end you would check for the illegal condition where other options were passed without aflag being set.
So all in all, it would look like this:
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
int
main (int argc, char *argv[])
{
int flags, opt;
int nsecs, tfnd;
int aflag;
nsecs = 0;
tfnd = 0;
flags = 0;
aflag = 0;
while ((opt = getopt (argc, argv, "ant:")) != -1)
{
switch (opt)
{
case 'a':
aflag = 1;
break;
case 'n':
flags = 1;
break;
case 't':
nsecs = atoi (optarg);
tfnd = 1;
break;
default: /* '?' */
fprintf (stderr, "Usage: %s [-t nsecs] [-n] name\n", argv[0]);
exit (EXIT_FAILURE);
}
}
printf ("flags=%d; tfnd=%d; optind=%d\n", flags, tfnd, optind);
if (optind >= argc)
{
fprintf (stderr, "Expected argument after options\n");
exit (EXIT_FAILURE);
}
if (!aflag && (flags || tfnd))
{
fprintf (stderr, "Must specify a flag to use n or t flag\n");
exit (EXIT_FAILURE);
}
printf ("name argument = %s\n", argv[optind]);
/* Other code omitted */
exit (EXIT_SUCCESS);
}

How to get a value from optarg

Hi I am writing a simple client-server program. In this program I have to use getopt() to get the port number and ip address like this:
server -i 127.0.0.1 -p 10001
I do not know how can I get values from optarg, to use later in the program.
You use a while loop to move through all the arguments and process them like so ...
#include <unistd.h>
int main(int argc, char *argv[])
{
int option = -1;
char *addr, *port;
while ((option = getopt (argc, argv, "i:p:")) != -1)
{
switch (option)
{
case 'i':
addr = strdup(optarg);
break;
case 'p':
port = strdup(optarg);
break;
default:
/* unrecognised option ... add your error condition */
break;
}
}
/* rest of program */
return 0;
}
How about like this:
char buf[BUFSIZE+1];
snprintf(buf,BUFSIZE,"%s",optarg);
Or in a more complete example:
#include <stdio.h>
#include <unistd.h>
#define BUFSIZE 16
int main( int argc, char **argv )
{
char c;
char port[BUFSIZE+1];
char addr[BUFSIZE+1];
while(( c = getopt( argc, argv, "i:p:" )) != -1 )
switch ( c )
{
case 'i':
snprintf( addr, BUFSIZE, "%s", optarg );
break;
case 'p':
snprintf( port, BUFSIZE, "%s", optarg );
break;
case '?':
fprintf( stderr, "Unrecognized option!\n" );
break;
}
return 0;
}
For more information see the documentation of Getopt.
It is one of the numerous flaws of the getopt documentation: it does not state clearly that optarg must be copied for later use (using strdup(), for instance) because it may be overwritten by later options or just plain freed by getopt.
In the case of an ip and port you don't need to store the strings. Just parse them and store the values in a sockaddr.
#include <arpa/inet.h> // for inet_ntop, inet_pton
#include <getopt.h> // for getopt, optarg
#include <netinet/in.h> // for sockaddr_in, etc
#include <stdio.h> // for fprintf, printf, stderr
#include <stdlib.h> // for atoi, EXIT_SUCCESS
#include <string.h> // for memset
#include <sys/socket.h> // for AF_INET
int main(int argc, char *argv[])
{
struct sockaddr_in sa;
char c;
memset(&sa, 0, sizeof(sa));
sa.sin_family = AF_INET;
sa.sin_addr.s_addr = htonl(INADDR_ANY);
sa.sin_port = 0;
while ((c = getopt(argc, argv, "i:p:")) != -1)
{
switch (c)
{
case 'p':
sa.sin_port = htons(atoi(optarg));
break;
case 'i':
inet_pton(AF_INET, optarg, &(sa.sin_addr));
break;
case '?':
fprintf(stderr, "Unknown option\n");
break;
} /* ----- end switch ----- */
}
char str[INET_ADDRSTRLEN];
inet_ntop(AF_INET, &(sa.sin_addr), str, INET_ADDRSTRLEN);
printf("%s:%d\n", str, ntohs(sa.sin_port));
return EXIT_SUCCESS;
} /* ---------- end of function main ---------- */

Resources