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.
Related
I'm working on a socket program. I need to get informations regarding the adress of a server from a document. I need to be able to change what document I get those informations from when I run the executable.
For example, if my program is called client.c, I need to be able to type in the terminal : ./client -c Name_Of_The_Document, and then the program will get these informations from the document Name_Of_The_Document.
I have no idea how to implement this "-c" option and I don't even know what to type on google or anything. Thanks to anyone that could help me
I have all the code to read in the document working, I just need to know how to change what document I want to read in form the terminal when running the executable.
If you declare your main() function as
int main (int argc, char *argv[])
{
return 0;
}
arguments passed to your program will appear in the argv parameters as strings.
An example of how to query them is given here.
You can then implement the code which handles opening and reading the file.
You need to use getopt function. Here is an example:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main (int argc, char **argv)
{
char *cvalue = NULL;
int index;
int c;
opterr = 0;
while ((c = getopt (argc, argv, "c:")) != -1)
switch (c)
{
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 ("cvalue = %s\n", cvalue);
for (index = optind; index < argc; index++)
printf ("Non-option argument %s\n", argv[index]);
return 0;
}
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.
I'm trying to use getopt in order to run two different functions depending on the arguments given.
int main(int argc, char **argv) {
int i;
int identify;
while ((identify = getopt(argc, argv, "c:")) != -1) {
switch (identify) {
case 'c':
for (i = 2; i < argc; i++) {
readerC(argv[i]);
}
default:
for (i = 2; i < argc; i++) {
reader(argv[i]);
}
}
}
return(0);
}
The purpose is that, if the command included "-c", then it would run the "readerC" function. If there were no arguments passed, then it would read the "reader" function.
I've revised the above function multiple times, but I can't seem to be able to run the "reader" function when running the command with no arguments (there is no output). Previously, putting in -c would run the readerC command as required, but after messing around with it, it now runs the readerC function followed by the reader function.
I tried changing "default:" to "case ':'" and "case '?'" but that hasn't worked either. Any help would be greatly appreciated :)
You forgot to add break statements. Without a break, control simply falls through to the next case. Here is the code with break statements inserted into the relevant places:
while ((identify = getopt(argc, argv, "c:")) != -1) {
for (i = 2; i < argc; i++) {
switch (identify) {
case 'c':
for (i = 2; i < argc; i++) {
readerC(argv[i]);
}
break;
default:
for (i = 2; i < argc; i++) {
reader(argv[i]);
}
break; /* not really needed but for completeness */
}
}
}
Also, it seems like you are using the same i for all nested loops. Are you sure that's what you want? You might also want to have a look at the optarg variable which points to the argument corresponding to the currently parsed option.
Maybe also read about how getopt works again because it seems like you haven't quite understood it. These loops you wrote are somewhat strange.
The sequence for a main() program handling options is often:
Initialization
Option parsing
Do the real work
You should process the options with getopt(), then process the file arguments. You also need to include break in your switch statement as C does not break automatically between cases.
Hence, you might end up with:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static void reader(const char *file);
static void readerC(const char *file);
int main(int argc, char **argv)
{
void (*function)(const char *arg) = reader;
int opt;
while ((opt = getopt(argc, argv, "c")) != -1)
{
switch (opt)
{
case 'c':
function = readerC;
break;
default:
fprintf(stderr, "Unrecognized option %c\n", optopt);
exit(1);
}
}
if (optind == argc)
{
fprintf(stderr, "Usage: %s [-c] file ...\n", argv[0]);
exit(1);
}
for (int i = optind; i < argc; i++)
{
(*function)(argv[i]); // The old-fashioned way
// function(argv[i]); // The more modern way
}
return(0);
}
If you're not comfortable with function pointers yet, then you can use a flag instead:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
static void reader(const char *file);
static void readerC(const char *file);
int main(int argc, char **argv)
{
int cflag = 0;
int opt;
while ((opt = getopt(argc, argv, "c")) != -1)
{
switch (opt)
{
case 'c':
cflag = 1;
break;
default:
fprintf(stderr, "Unrecognized option %c\n", optopt);
exit(1);
}
}
if (optind == argc)
{
fprintf(stderr, "Usage: %s [-c] file ...\n", argv[0]);
exit(1);
}
for (int i = optind; i < argc; i++)
{
if (cflag)
readerC(argv[i]);
else
reader(argv[i]);
}
return(0);
}
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);
}
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);
}