What I want to do is to get more arguments from the command line and get them output each one on a new line. How could I do that by keeping the same structure? I want also to get the -f output.
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <getopt.h>
int
main(int argc, char *argv[])
{
int nod1, opt;
int nsecs, nod2;
nsecs = 0;
nod2 = 0;
nod1 = 0;
while ((opt = getopt(argc, argv, "nf:")) != -1) {
switch (opt) {
case 'n':
nod1 = 1;
break;
case 'f':
nsecs = atoi(optarg);
nod2 = 1;
break;
default: /* '?' */
fprintf(stderr, "Usage: %s [-t nsecs] [-n] name\n",
argv[0]);
exit(EXIT_FAILURE);
}
}
printf("nod1=%d; nod2=%d; optind=%d\n", nod1, nod2, optind);
if (optind >= argc) {
fprintf(stderr, "Expected argument after options\n");
exit(EXIT_FAILURE);
}
printf("Output = %s\n", argv[optind]);
/* Other code omitted */
exit(EXIT_SUCCESS);
}
From a comment:
The arguments after the -f should be optional and I want to list every single one that has been passed under one another...
$ ./partitioner -n 4 -f Test1 Test2 Test3 Test4
Number:4
File names:
Output = Test1
Output = Test2
Output = Test3
Output = Test4
$
Having in account the comment made by Jonathan Leffler I edit my answer:
POSIX getopt() doesn't really handle optional arguments sensibly. GNU getopt() is a bit better, but not by much. Avoid them whenever you can.
I come out with a simple idea, but one that could solve your problem so here it is:
In argv you have a list of arguments ordered as they was in the commend line right? So, if you can find any -f in argv that means all arguments following -f until another option or the end of the argument list are the options you want to print.
From -f to another option(-g in this case):
./command -a A -b B -f one two tree -g G
From -f to the end.
./command -a A -b B -f one two tree
Here you have a helper function for doing that:
bool get_f_args(int argc, char *argv[], int &count, int* indexes)
{
bool f_found = false, parsing_f_args = false;
int collect_count = 0;
if (argc < 3) return false; // "./command -f" are just two values for argv
// we need at least 3.
// Check for every argument in the argument list.
for (int i = 1; i < argc; i++)
{
// If you found another option
// stop collecting args.
if (argv[i][0] == '-' && parsing_f_args) // options starts with '-' character.
parsing_f_args = false;
if (parsing_f_args)
indexes[count++] = i;
// If some is "-f" then the following are the
// ones you're looking for. We check for -f after
//
// indexes[count++] = i;
//
// in roder to avoid adding -f index to indexes.
if (strcmp("-f", argv[i]) == 0) {
parsing_f_args = true;
f_found = true;
}
}
return f_found;
}
And here is an example of use:
int main(int argc, char* argv[])
{
int count = 0;
int indexes[10];
bool f_found = get_f_args(argc, argv, count, indexes);
if (f_found){
for (int i = 0; i < count; i++)
printf("Ouput = %s\n", argv[indexes[i]]);
}
return 0;
}
Related
Consider a file ArgumentFile.txt
int a=100;
int b[3] = { 5, 2, 5 };
double c = 0.0014;
And the main code code.c
int main(int argc, char *argv[])
{
if (argc > 1) FILE *f = fopen(argv[1], "r");
ParseFile(f); // Set the parameters based on file
DoStuff(a,b,c); // Run the process based on the parsed arguments
}
A user could then pass arguments by doing
./CodeExecutable ArgumentFile.txt
Is there a standard solution to parse arguments from file? It would be an equivalent of getopt which parse arguments from command line?
You do not need an equivalent to getopt() you can use exactly getopt(). The getopt() function does not specifically process command line arguments; it will process any array of pointers to strings in the style of command line arguments.
#define MAX_ARGS 256
#define MAX_FILE_LEN 4096
int main(int argc, char *argv[])
{
if( argc > 1 )
{
FILE *f = fopen(argv[1], "r");
if( f != 0 )
{
char fargs[MAX_FILE_LEN] = "" ;
fread( fargs, 1, MAX_FILE_LEN, f ) ;
// Build fargv from file content
char* fargv[MAX_ARGS] ;
int fargc = 0 ;
fargv[fargc] = strtok( fargs, " \n\r" ) ;
while( fargc < MAX_ARGS && fargv[fargc] != 0 )
{
fargc++ ;
fargv[fargc] = strtok( 0, "\n\r" ) ;
}
// Process fargv using getopt()
while( (char c = getopt( fargc, fargv, "a:b:c:")) != -1 )
{
switch( c )
{
...
}
}
}
}
...
return 0 ;
}
It is probably better to dynamically allocate fargs using teh actual file length, but the above is illustrative only.
Your input file might then look like:
-a 100
-b 5,2,5
-c 0.0014
The getopt() loop will then have to process the arguments as necessary - using sscanf() for example.
switch( c )
{
case 'a' : sscanf( optarg, "%i", a ) ; break ;
case 'b' : sscanf( optarg, "%i,%i,%i", b[0], b[1], b[2] ) ; break ;
case 'c' : sscanf( optarg, "%f", c ) ; break ;
}
DoStuff( a, b, c ) ;
I use getopt(). Here is an example that allows for some more flexibility. This example demonstrates how th handle for optional optarg and multiple optargs.
#include <stdio.h>
#include <unistd.h>
#include <string.h>
void usage(void)
{
printf("usage: \n"
"This example demonstrates how to add flexibility to the traditional linux getopt()\n"
"This help text is printed if the program is executed without arguments\n"
"or with an invalid argument configuration.\n"
"to view the help file run without arguments or with -h\n"
"Oterwise the program accepts two options: -d, -u\n"
"-d: can come with 0 or one option argument\n"
"-u: can come with one or more option arguments\n"
"try this to see the output:\n"
"./test -d aaa -u ccc 4 \"quoted multi token string\" -d -u\n");
}
int main(int argc, char **argv)
{
char data[101];
int opt;
memset(data, 0, 101);
while ((opt = getopt(argc, argv, "hd:u:t:")) != -1) {
switch (opt) {
case 'h':
usage();
return 0;
case 'd': // can accept 0 or 1 parameters
if (optarg[0] == '-') { //not an optarg of ours...
optind--;
printf("option: -d. no tokens (another option follows)\n");
break;
}
strncpy(data, optarg, 100);
printf("option: -d. tokens: %s\n", data);
break;
case 'u': //can accept one or more parameters ...
strncpy(data, optarg, 100);
printf("option: -u. tokens: %s", data);
//do we have more arguments for 'u'?
while( optind <= argc && argv[optind][0] != '-') {
strncpy(data, argv[optind], 100);
printf(", %s", data);
optind++;
}
printf(".\n");
break;
case ':': //this happens if we got an option which expects an arg without any optarg.
if(optopt == 'd') {//lets allow a '-d' without its optarg
printf("option: -d. no tokens\n");
break;
}
//otherwise fall through to the default handler
default: //covers ':' '?' for missing value, '-h' for help, etc.
printf("on error you get: opt=%c. optopt=%c opterr=%d\n", opt, optopt, opterr);
return 0;
}
}
return 0;
}
You can't do that using plain C code. You'll have to write platform specific assembly language code to handle that.
Your best option is to use the C proprocessor.
int main(int argc, char *argv[])
{
#include "myfile.txt"
// Do Stuff
}
Having said that, I don't know what you would gain by that instead of putting the contents of myfile.txt in main() directly.
I have an assignment in C that requires options to be read in for different forms of a program. Before I start on that, though, I want to make sure that the getopt portion is working fine. However, the program keeps dropping the last parameter and I don't know why. Whenever I enter the last char, the program goes to the default value that kills the program. Any help is appreciated!
#include<unistd.h>
#include<stdio.h>
#include<stdlib.h>
#include<ctype.h>
int main(int argc, char **argv)
{
int sFlag = 0;
int lFlag = 0;
int dFlag = 0;
int rFlag = 0;
int c;
opterr = 0;
while ((c = getopt (argc, argv, "slr:")) != -1)
{
switch(c)
{
case 's':
sFlag = 1;
break;
case 'l':
lFlag = 1;
break;
case 'r':
rFlag = 1;
break;
default:
printf("unknown parameter introduced");
exit(-1);
break;
}
}
printf("s = %i, l = %i, d = %i, r = %i", sFlag, lFlag, dFlag, rFlag);
return 1;
}
The colon symbol after r in "slr:" tells getopt() to wait for a mandatory argument which follows -r.
Examples:
getopt(argc, argv, "slr:") can parse ./project -s -l -r r_arg (or ./project -r r_arg -s etc.)
getopt(argc, argv, "s:lr:") can parse ./project -s s_arg -l -r r_arg
getopt(argc, argv, "s:lr:") can also parse ./project -s -l -r r_arg with no error, but the program works differently from user's expectation. This is because getopt() expects -s to be followed by its argument, however it looks like, so the next argument -l is consumed and will not hit your switch(c).
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.
Quick Edit: This is a homework assignment. My goal is to take in a few cl arguments for my program (either -s, -w with a width length, and the file) and word wrap the file that according the default length of 40 characters or a new number if the user chooses the '-w' option.
I'm trying to write a C program that takes in the arguments via command prompt (the executable is named "wrapfile.exe"). The program isn't done and more is to be added, this is just a part of it that is causing me mayhem.
Here would be an example of valid command prompt entries:
C:\"within wrapfile.exe's directory"> wrapfile -s filename.txt
C:\"within wrapfile.exe's directory"> wrapfile -w 5 filename.txt
C:\"within wrapfile.exe's directory"> wrapfile -s -w 50 filename.txt
etc.
Example of invalid entries:
C:\"within wrapfile.exe's directory"> wrapfile
C:\"within wrapfile.exe's directory"> wrapfile -w
C:\"within wrapfile.exe's directory"> wrapfile qwer
etc.
My issue is it cannot detect the number after I enter "-w" ..
Here is the code:
#include "stdio.h"
#include "stdlib.h"
#include "io.h"
#include "string.h"
int main(int argc, char *argv[])
{
int output = 0;
int commands = 1;
int wraplength= 41;
int i=0;
int counter=0;
int wordwrap = 0;
int ExitStatus = 1;
int input = 1;
int w = 0;
int s = 0;
FILE *f = NULL;
for (i=0; i < argc; i++)
{
if ( (*argv[input] + i-1) == '-') // check for option
{
printf(" - detected first");
if (*(argv[input] + i ) == 's') // check for wordwrap
{
printf(" s detected");
i++;
i++;
s = 1; // set s to true to that option can be added later
wordwrap = 1; // set wordwrap on or true
}
if (*(argv[input] + i) == 'w')//if the second option is a w
{
i++;
printf(" w detected ");
sscanf ((argv[input] + i), "%d", &wraplength);
printf ("%d", wraplength);
if ( wraplength < 1) // check what the number is
{
printf("Usage: wrapfile [-s] [-w width] file ...");
return 2; // command line options incorrect
}
}
if (*(argv[input] + i) == '-')
{
printf(" second - detected");
i++;
if (*(argv[input]+ i) == 'w')//if the second option is a w
{
i++;
if (sscanf ((argv[(input)+1]), "%d", &wraplength) != 1) // check what the number is
{
printf("Usage: wrapfile [-s] [-w width] file ...");
return 2; // command line options incorrect
}
}
}
}
}
return 0;
}
BIG EDIT:
I took Dietrich Epp suggestion and here is something I did with it. It seems my program crashes every time I try to check an argument after "-s". How can I check the next arguments (if there is none?) without crashing my program. I know that this line has something to do with the crashing:
arg = argv[i++];
Here's the code:
while (i < argc)
{
arg = argv[i++];
if (!strcmp(arg, "-s"))
{
arg = argv[i++];
son = 1;
printf("Have -s\n");
if (!strcmp(arg, "-w"))
{
if (i >= argc)
{
printf("Usage: wrapfile [-s] [-w width] file ...");
}
param = argv[i++];
wraplength = *param;
printf("Have -w %s\n", param);
}
}
I think you're mixing up your loop variables here.
This makes i loop over all arguments, including argv[0] which you usually don't want.
for (i=0; i < argc; i++)
This uses i as an index into one of the argument strings, but with funny syntax.
if (*(argv[input] + i ) == 's')
On other systems you'd just use getopt(), but that's not always an option on Windows.
Suggestion
You'll want a loop more like this:
// Note: C99, so you will need to translate to C89 if you use Microsoft's
// C compiler
int i = 1;
while (i < argc) {
char *arg = argv[i++];
if (!strcmp(arg, "-s")) {
printf("Have -s\n");
} else if (!strcmp(arg, "-w")) {
if (i >= argc)
error();
char *param = argv[i++];
printf("Have -w %s\n", param);
} else {
error();
}
}
Command option parsing is so incredibly not relevant to your program's performance that the above chain of if/else blocks and strcmp() are fine.
Warning!
You will not be able to specify arbitrary filenames with this! If you get the arguments from main(), they will be converted to whichever code page you are currently using, which is horribly broken for almost any purpose. (It might be fine if you are the only one using the program.)
In order to specify arbitrary filenames, you will need to call GetCommandLineW() to get the command line in UTF-16, and then CommandLineToArgvW() to parse it to int argc and wchar_t **argv.
Hello I'm new with C and I'm trying to start this lab where the command syntax is to first list any command line flags then list one or more file names.
I'm having trouble organizing how I want to scan the input arguments and differentiating them between flags and file names.
I thought of doing a loop to see if the argument is a flag or file name. But I'm unsure how to begin implementing it. Since the first 4 arguments can be potential flags in any order then anything after is the file name. But it is also possible for no flags to be given and just start with filenames. I don't know at all how to initalize this loop to go through each argument 1 by 1. Can anyone help please?
Example of possible command line arguments:
wc fcopy.c head.c (no flags given just file names)
wc -l -c -w -L fcopy.c head.c a.exe (flags given and multiple files)
wc -l -w -c -L fcopy.c (flags given and 1 file name)
Reading command line args one by one is pretty simple:
int main( int argc, // Number of strings in array argv char *argv[])
The two basic args to a C function are argc (int number of args), and argv (an array of strings for the args)
The first string is always the name of the program that is running, after that is the args that were passed over the command line.
if(argc > 1)
for( count = 1 count < argc; count++ )
printf("%s", argv[count]);
Will display to the screen each of the arguments passed in past the name of the calling program.
I assume your flags are passed with a "-" as the first character? If so, you can check the contents of the first character in each string for a '-' to tell if its a flag or not.
You can use getopt()
Check these questions:
Parsing command-line arguments?
Handling command line options before and after an argument in C
Argument-parsing helpers for C/UNIX
Getopt shift optarg
Check out getopt, it allows you to parse command line arguments and their flags:
#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;
}
Example of Parsing Arguments with getopt
Also see http://www.gnu.org/software/libc/manual/html_node/Example-of-Getopt.html