opterr declaration in getopt - c

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.

Related

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 Text conversion program

I am very new to the C language and have been working on a program that takes either a text file or input from the keyboard and either turns all the letters to capitals, lowercase, or rotates them by 13 places depending on the input given by the user which should go something like: ./tconv -u test.txt
This should, in theory, turn all the letters in test.txt to uppercase letters. If no file is given, ./tconv -u, then it should take input from the keyboard.
I think I am missing something fairly simple, but when I run it with any -r,-u, or -l arguments, it says it cannot read "-r", "-u", or"-l". What am I missing?
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <strings.h>
FILE*
input_from_args(int argc, const char *argv[])
{
if (argc==1){
return stdin;
}else{
return fopen(argv[1],"r");
}
}
int
rot13(c)
{
int e;
int ROT;
ROT = 13;
if(c>='A' && c <='Z'){
if((e=c+ROT)<='Z')
return e;
else{
e = c - ROT;
return e;
}
}
else{
return c;
}
}
int
main(int argc, const char*argv[])
{
FILE *src = input_from_args(argc,argv);
FILE *dest = stdout;
if (src == NULL){
fprintf(stderr, "%s: unable to open %s\n", argv[0], argv[1]);
exit(EXIT_FAILURE);
}
char *rotate = "-r";
char *lower = "-l";
char *upper = "-u";
int i;
i =0;
int ch;
while ((ch = fgetc(src))!=EOF){
if (strcmp(upper,argv[i])==0){
fprintf(dest,"%c",toupper(ch));
}
else if (strcmp(lower,argv[i])==0){
fprintf(dest,"%c",tolower(ch));
}
else if (strcmp(rotate,argv[i])==0){
fprintf(dest,"%c",rot13(ch));
}
else{
fprintf(dest,"%c",ch);
}
}
fclose(src);
return EXIT_SUCCESS;
}
Argv[0] is your program, argv[1] is your flag and argv[2] is the file name if you provided one. You are trying to open argv[1] a file named "-r"
If you are using linux platform you can look into getopt_long to parse the command line options. it is provided by GNU for linux systems and it is system dependent. For system independent command line parsing Google gflags
This will help to reduce the overhead of command line parsing and you can concentrate more on program logic.
Here is an example taken from http://www.gnu.org/software/libc/manual/html_node/Getopt-Long-Option-Example.html
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
/* Flag set by ‘--verbose’. */
static int verbose_flag;
int
main (int argc, char **argv)
{
int c;
while (1)
{
static struct option long_options[] =
{
/* These options set a flag. */
{"verbose", no_argument, &verbose_flag, 1},
{"brief", no_argument, &verbose_flag, 0},
/* These options don’t set a flag.
We distinguish them by their indices. */
{"add", no_argument, 0, 'a'},
{"append", no_argument, 0, 'b'},
{"delete", required_argument, 0, 'd'},
{"create", required_argument, 0, 'c'},
{"file", required_argument, 0, 'f'},
{0, 0, 0, 0}
};
/* getopt_long stores the option index here. */
int option_index = 0;
c = getopt_long (argc, argv, "abc:d:f:",
long_options, &option_index);
/* Detect the end of the options. */
if (c == -1)
break;
switch (c)
{
case 0:
/* If this option set a flag, do nothing else now. */
if (long_options[option_index].flag != 0)
break;
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case 'a':
puts ("option -a\n");
break;
case 'b':
puts ("option -b\n");
break;
case 'c':
printf ("option -c with value `%s'\n", optarg);
break;
case 'd':
printf ("option -d with value `%s'\n", optarg);
break;
case 'f':
printf ("option -f with value `%s'\n", optarg);
break;
case '?':
/* getopt_long already printed an error message. */
break;
default:
abort ();
}
}
/* Instead of reporting ‘--verbose’
and ‘--brief’ as they are encountered,
we report the final status resulting from them. */
if (verbose_flag)
puts ("verbose flag is set");
/* Print any remaining command line arguments (not options). */
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
putchar ('\n');
}
exit (0);
}

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);
}

getopt is not working for one of my parameters

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

Pass arguments into C program from command line

So I'm in Linux and I want to have a program accept arguments when you execute it from the command line.
For example,
./myprogram 42 -b -s
So then the program would store that number 42 as an int and execute certain parts of code depending on what arguments it gets like -b or -s.
You could use getopt.
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main (int argc, char **argv)
{
int bflag = 0;
int sflag = 0;
int index;
int c;
opterr = 0;
while ((c = getopt (argc, argv, "bs")) != -1)
switch (c)
{
case 'b':
bflag = 1;
break;
case 's':
sflag = 1;
break;
case '?':
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 ("bflag = %d, sflag = %d\n", bflag, sflag);
for (index = optind; index < argc; index++)
printf ("Non-option argument %s\n", argv[index]);
return 0;
}
In C, this is done using arguments passed to your main() function:
int main(int argc, char *argv[])
{
int i = 0;
for (i = 0; i < argc; i++) {
printf("argv[%d] = %s\n", i, argv[i]);
}
return 0;
}
More information can be found online such as this Arguments to main article.
Consider using getopt_long(). It allows both short and long options in any combination.
#include <stdio.h>
#include <stdlib.h>
#include <getopt.h>
/* Flag set by `--verbose'. */
static int verbose_flag;
int
main (int argc, char *argv[])
{
while (1)
{
static struct option long_options[] =
{
/* This option set a flag. */
{"verbose", no_argument, &verbose_flag, 1},
/* These options don't set a flag.
We distinguish them by their indices. */
{"blip", no_argument, 0, 'b'},
{"slip", no_argument, 0, 's'},
{0, 0, 0, 0}
};
/* getopt_long stores the option index here. */
int option_index = 0;
int c = getopt_long (argc, argv, "bs",
long_options, &option_index);
/* Detect the end of the options. */
if (c == -1)
break;
switch (c)
{
case 0:
/* If this option set a flag, do nothing else now. */
if (long_options[option_index].flag != 0)
break;
printf ("option %s", long_options[option_index].name);
if (optarg)
printf (" with arg %s", optarg);
printf ("\n");
break;
case 'b':
puts ("option -b\n");
break;
case 's':
puts ("option -s\n");
break;
case '?':
/* getopt_long already printed an error message. */
break;
default:
abort ();
}
}
if (verbose_flag)
puts ("verbose flag is set");
/* Print any remaining command line arguments (not options). */
if (optind < argc)
{
printf ("non-option ARGV-elements: ");
while (optind < argc)
printf ("%s ", argv[optind++]);
putchar ('\n');
}
return 0;
}
Related:
Which command line commands style do you prefer?
What is the general syntax of a Unix shell command?
Take a look at the getopt library; it's pretty much the gold standard for this sort of thing.
Instead of getopt(), you may also consider using argp_parse() (an alternative interface to the same library).
From libc manual:
getopt is more standard (the
short-option only version of it is a
part of the POSIX standard), but using
argp_parse is often easier, both for
very simple and very complex option
structures, because it does more of
the dirty work for you.
But I was always happy with the standard getopt.
N.B. GNU getopt with getopt_long is GNU LGPL.
Other have hit this one on the head:
the standard arguments to main(int argc, char **argv) give you direct access to the command line (after it has been mangled and tokenized by the shell)
there are very standard facility to parse the command line: getopt() and getopt_long()
but as you've seen the code to use them is a bit wordy, and quite idomatic. I generally push it out of view with something like:
typedef
struct options_struct {
int some_flag;
int other_flage;
char *use_file;
} opt_t;
/* Parses the command line and fills the options structure,
* returns non-zero on error */
int parse_options(opt_t *opts, int argc, char **argv);
Then first thing in main:
int main(int argc, char **argv){
opt_t opts;
if (parse_options(&opts,argc,argv)){
...
}
...
}
Or you could use one of the solutions suggested in Argument-parsing helpers for C/UNIX.

Resources