I have a c program which should take the first argument and check which function matches it.
Example:
./test.o blabla
Code:
main(int argc, const char* argv) {
switch (argv[1]) {
case "blabla":
do_omething(argv[2]); break;
}
return 0;
}
void do_something(const char* param) {
// ....
}
What is the best way to achieve this?
If you switch on a C string, that's its address, not its contents.
You should use something like strcmp to check if the content matches:
if (strcmp (argv[1], "blabla") == 0)
do_something(argv[2]);
Not sure what your requirement is but may be you can do something like below
switch(*argv[1){
case 'b':
if (strcmp (argv[1], "blabla") == 0)
do_it_for_blabla();
break;
case 'c':
if( compare with wait ever )
do_what_ever();
break;
default:
//do nothing and break;
break;
}
Related
I wanted to use getopt_long() twice in a routine so that a verbosity flag can be set before parsing everything else but somehow the second call of the function does not process the arguments as expected. Here is a simplified code that demonstrates the issue. Anyone has any clues?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
static void processInput(int argc, const char **argv) {
int k;
int verbose = 0;
struct option long_options[] = {
{"help" , no_argument, NULL, 'h'},
{"verbose", no_argument, NULL, 'v'},
{0, 0, 0, 0}
};
// Construct short_options from long_options
char str[1024] = "";
for (k = 0; k < sizeof(long_options) / sizeof(struct option); k++) {
struct option *o = &long_options[k];
snprintf(str + strlen(str), 1023, "%c%s", o->val, o->has_arg == required_argument ? ":" : (o->has_arg == optional_argument ? "::" : ""));
}
// First pass: just check for verbosity level
int opt, long_index = 0;
while ((opt = getopt_long(argc, (char * const *)argv, str, long_options, &long_index)) != -1) {
printf("Processing %c\n", opt);
switch (opt) {
case 'v':
verbose++;
break;
default:
break;
}
}
//
// Add verbose flag here to show something while setting up
//
// Second pass: now we go through all of them.
long_index = 0;
while ((opt = getopt_long(argc, (char * const *)argv, str, long_options, &long_index)) != -1) {
printf("Processing %c\n", opt);
switch (opt) {
case 'h':
printf("Help text here\n");
break;
case 'v':
// Add a dummy line here so that '-v' does not trigger the default task
break;
default:
fprintf(stderr, "I don't understand: -%c optarg = %s\n", opt, optarg);
exit(EXIT_FAILURE);
break;
}
}
}
int main(int argc, const char **argv) {
processInput(argc, argv);
return EXIT_SUCCESS;
}
The global variable optind is increased to argc by the end of getopt_long() routine so the second pass simply would not go further. In order to have the function reprocess everything from the beginning again, the global variable optind needed to be reset. So, add
// Second pass: now we go through all of them.
optind = 1;
long_index = 0;
As stated is the man page of getopt_long :
The variable optind is the index of the next element to be processed in argv. The system initializes this value to 1. The caller can reset it to 1 to restart scanning of the same argv, or when scanning a new argument vector.
So you have to set optind to 1 before the second pass.
// Second pass: now we go through all of them.
optind = 1;
long_index = 0;
while ((opt = getopt_long(argc, (char * const *)argv, str, long_options, &long_index)) != -1) {
printf("Processing %c\n", opt);
switch (opt) {
case 'h':
printf("Help text here\n");
break;
case 'v':
// Add a dummy line here so that '-v' does not trigger the default task
break;
default:
fprintf(stderr, "I don't understand: -%c optarg = %s\n", opt, optarg);
exit(EXIT_FAILURE);
break;
}
}
Little warning : Further on the man, there is this note :
A program that scans multiple argument vectors, or rescans the same vector more than once, and wants to make use of GNU extensions such as '+' and '-' at the start of optstring, or changes the value of POSIXLY_CORRECT between scans, must reinitialize getopt() by resetting optind to 0, rather than the traditional value of 1. (Resetting to 0 forces the invocation of an internal initialization routine that rechecks POSIXLY_CORRECT and checks for GNU extensions in optstring.)
So be carefull and choose what it most suit your situation.
void display(char * str){
printf("%s: Missing file\n", str);
}
int main(int argc, char **argv)
{
int longIndex, opt = 0;
const char *optString = "h?";
static const struct option longOpts[] = {
{ "help", no_argument, NULL, 'h' },
{ NULL, no_argument, NULL, 0 }
};
opt = getopt_long( argc, argv, optString, longOpts, &longIndex );
while( opt != -1 ) {
switch( opt ) {
case 'h':
case '?':
display(argv[0]);
break;
default:
break;
}
opt = getopt_long( argc, argv, optString, longOpts, &longIndex );
}
return 0;
}
This code compiles fine but when I run it like:
./a.out ?
it does not call display. What am I missing?
The question mark '?' is returned by getopt when it finds an argument that's not in the optstring or if it detects a missing option argument, so you shouldn't use '?' in optstring because it's sort of reserved for that, instead you should use the more conventional 'h' for help.
See the man page
Edit:
This is an example:
switch (opt) {
case 'n':
some_flag = 1;
break;
case 'h': /* help */
default: /* '?' unknown opt or missing arg*/
fprintf(stderr, "Usage: %s [-n nsecs] \n", argv[0]);
exit(EXIT_FAILURE);
}
If you include -? with --help on your help message, leave the question mark out of your call to getopt, leave it out of the case option, and make sure that --help is the first case option in your list, the question mark works as you'd want it to.
const char *optString = "h?";
Above line replace with following line
const char *optString = "h\?";
this is the literal of question mark in C language
When I am writing a piece of code, say something like this:
int i_flag;
char *s;
while ((c = getopt (argc, argv, "i::o:")) != -1) // I know "i::" is a GNU extension
switch (c) {
case 'i':
i_flag = 1;
if (optarg != NULL)
str-i = optarg;
break;
case 'o':
id = strtol (optarg, &s, 0);
if (id < 0 || id > 5 || *s) {
fprintf(stderr, "Invalid ID: %s\n", optarg);
print_usage(); // this function exit()'s the program
}
break;
default:
print_usage();
}
My question is that I know optarg can be NULL in the 'i' case, but can it be NULL in the 'o' case? I think it should not be NULL at all, but it does not seem to be guaranteed in POSIX.
I have this question since a very smart static analyzer looks at if (optarg != NULL) and says "Oh, so optarg can be NULL and you didn't check it in case 'o'.
Update: Fix int i-flag;.
Yes, optarg will be non-null. If a argument is omitted for an option that requires one, getopt will return '?'.
I need help to display name to command line like this (I don't know how to explain) in C
$:Enter your name: Test
$:Test>
But when you continue press enter it still showing Test>
$:Test>
$:Test>
So how do we get argv[0] and do something like this (Sorry that I cannot explain probably)
Thank you
command line arguments are stored in char **argv, and there are argc of them.
int main(int argc, char **argv)
{
int i=0;
for(i=0; i< argc; i++)
printf("argument number %d = %s\n", i, argv[i]);
return 0;
}
argv[0] is the name of the program being executed, so argc is always at least == 1 ( or more)
If you had rather shell-like program in mind, maybe the following couldbe of use:
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#define BUFSIZE 64
int main() {
char prompt[BUFSIZE];
char command[BUFSIZE];
char *prefix = "$:";
char *suffix = ">";
printf("%s%s%s", prefix, "Enter your name:", suffix);
fgets(prompt, BUFSIZE, stdin);
prompt[strlen(prompt)-1] = '\0'; // get rid of the \n
while (true) {
printf("%s%s%s", prefix, prompt, suffix);
fgets(command, BUFSIZE, stdin);
if (strncmp(command,"Quit",4) == 0)
break;
}
return 0;
}
Whenever possible, you should use getopt() so that the order of your parameters doesn't matter. For example, suppose you wanted to take an integer parameter for the size, an integer for the mode of execution, and a toggle to indicate whether to run in "quiet mode" or not. Further suppose that "-h" should print help and exit. Code like this will do the trick. The "s:m:hq" string indicates that "-s" and "-m" provide parameters, but the other flags don't.
int main() {
// parse the command-line options
int opt;
int size = DEFAULT_SIZE, mode = DEFAULT_MODE, quiet = 0;
while ((opt = getopt(argc, argv, "s:m:hq")) != -1) {
switch (opt) {
case 's': size = atoi(optarg); break;
case 'm': mode = atoi(optarg); break;
case 'q': quiet = 1; break;
case 'h': usage(); return 0;
}
}
// rest of code goes here
}
Of course, you should add error checking in case optarg is null.
Also, if you're using C++, "string(optarg)" is an appropriate way for your case statement to set a std::string to hold a value that is stored as a char* in argv.
I want the put a sub-option in a string so that I can use it as a file name for reading a file:
char *nvalue = NULL;
char *dvalue = NULL;
char *input = NULL;
char inputfilename[] = "\"";
int ar;
int main(int argc, char *argv[])
{
while ((ar = getopt(argc, argv, "hn:d:i:")) != -1)
switch (ar)
{
case 'h':
printf("something");
break; /* added */
case 'n':
nvalue = optarg;
if (isdigit(nvalue))
stop = atoi(nvalue);
else
printf("something\n");
break; /* added */
case 'd':
dvalue = optarg;
if (!strcmp(dvalue, "FCFS") || !strcmp(dvalue, "SSTF") ||
!strcmp(dvalue, "C-SCAN") || !strcmp(dvalue, "LOOK"))
;
else
printf("Invalid type of disk scheduling policy entered.\n");
break; /* added */
case 'i':
input = optarg;
strcpy(inputfilename, optarg);
printf("Filename :%s\n", inputfilename);
break;
}
/* ... */
}
So on the command line if I input:
./foobar -i hello
then I should be able to read the file with:
FILE *file = fopen(inputfilename, "r" );
any suggestions? answers?
thanks!
There are a number of problems with your code. I'm ignoring the absence of header files (assuming your code uses the correct ones so all functions have a prototype in scope before use). I'm also reformatting your code ruthlessly but without further comment.
char *nvalue = NULL;
char *dvalue = NULL;
char *input = NULL;
char inputfilename[] = "\"";
This allocated an array of two bytes as inputfilename. I hate to think what's going to happen when you use it.
int ar;
There is every reason why this variable should be local to the main function and no reason visible for it to be a global variable. Unless you have a header declaring them, the other variables should also be static - assuming that you need to access their values outside of main() without a convenient way to pass them as locals. Avoid global variables whenever possible.
int main(int argc, char *argv[])
{
while ((ar = getopt(argc, argv, "hn:d:i:")) != -1)
{
switch (ar)
{
case 'h':
printf("something");
Oops; no break, so the code drops through to the case 'n': code. C is not Pascal.
case 'n':
nvalue = optarg;
if (isdigit(nvalue))
stop = atoi(nvalue);
You haven't shown a declaration for stop. Unless you really need the string, you can do without nvalue, avoiding a global variable, which is always desirable.
else
printf("something\n");
Another missing break; I'm not going to point it out again.
case 'd':
dvalue = optarg;
if (strcmp(dvalue, "FCFS") == 0 ||
strcmp(dvalue, "SSTF") == 0 ||
strcmp(dvalue, "C-SCAN") == 0 ||
strcmp(dvalue, "LOOK" == 0)
{
I'd suggest a comment such as /* Nothing - dvalue is OK */. Or inverting the condition using De Morgan's theorem:
if (strcmp(dvalue, "FCFS") != 0 &&
strcmp(dvalue, "SSTF") != 0 &&
strcmp(dvalue, "C-SCAN") != 0 &&
strcmp(dvalue, "LOOK" != 0)
You might even decide to encapsulate that test into a function which tests the value against each element of an array of codes.
}
else
printf("Invalid type of disk scheduling policy entered.\n");
It would be courteous to provide a list of the acceptable values - which suddenly becomes another reason for having an array of valid values which you can use to generate the list. Very often, error messages should be reported on stderr (using fprintf()) rather than stdout.
case 'i':
input = optarg;
This assignment is sufficient.
strcpy(inputfilename, optarg);
Unless the user types a single-character file name, you've just overflowed the inputfilename array. You really didn't need to make a copy of the argument unless you're going to modify the name (for example, to add or change the extension on the name).
//strcat(inputfilename,"\"");
printf("Filename :%s\n", inputfilename);
}
You didn't include a default clause. Since ar will be assigned the value ? when the user-provided option is not recognized, this is normally your cue to provide a simple usage message and exit.