I'm trying to implement an 'ls' command that lists file and directories. I have set the incoming argument array to the following:
argv[0] = "./a.out"
argv[1] = "-l"
argv[2] = "test.c"
Here is my code (assume that the main function passes argc and argv to the function I_AM_LS):
#include "ls.h"
int I_AM_LS(int argc, char ** argv)
{
// 'INCLUDING_HIDDEN_FILE' indicates program performs ls including hidden files
// 'EXCLUDING_HIDDEN_FILE' indicates program performs ls excluding.
int hidden_flag = EXCLUDING_HIDDEN_FILE;
int detail_flag = SIMPLY; // default option in ls.
// 'IN_DETAIL' indicates program performs ls with additional information.
// 'SIMPLY' indicates program performs ls without.
char option;
int i;
DIR * dp;
while ((option = getopt(argc, argv, "al")) != -1)
{
switch (option)
{
case 'a':
hidden_flag = INCLUDING_HIDDEN_FILE;
break;
case 'l':
detail_flag = IN_DETAIL;
break;
default: /* '?' */
printf("invaild option.\n");
return -1;
}
}
if( argv[optind] != NULL && argv[optind + 1] != NULL) // multiple argument
{
; // I have not finished the corresponding code yet.
}
else
{
if( argv[optind] == NULL) // case 1
I_REALLY_CALL_ls("./", hidden_flag, detail_flag);
else
I_REALLY_CALL_ls(argv[optind], hidden_flag, detail_flag);
}
printf("optind %d %d\n", optind, argv[optind]);
return 0;
}
}
int main(int argc, const char * argv[])
{
I_AM_LS(argc, argv);
return 0;
}
After the initial parsing loop, the program doesn't enter into the if statement 'argv[optind] != NULL'. We know that optind is 2 and argv[optind] points to "test.c", not NULL, the same behaviour is seem in debug mode.
Are there any problems with passing argv and argc to the function I_AM_LS? What should I do?
Note : I'm working on Xcode on OS X.
if( argv[optind] == NULL) // case 1
I_REALLY_CALL_ls("./", hidden_flag, detail_flag);
else if( argv[optind] != NULL && argv[optind] != NULL)
{
;
}
The condition in this else if is argv[optind] != NULL, evaluated twice for no good reason. So if the first condition doesn't hold, this one does, you do nothing (;), and
else if( argv[optind] != NULL)
{
// single non-option arguemnt.
I_REALLY_CALL_ls(argv[optind], hidden_flag, detail_flag);
}
is unreachable.
Related
I am writing on a program that should get up to 3 options while they can be combined as well. The part look like in following:
char flag = 0; // to mark which options were set
int aopt = INT_MAX; // default to INT_MAX if no args delivered
char bemerkung[100];
memset(bemerkung, '\0', 100); // string to receive via '-b'
char option;
while((option = getopt (argc, argv, "m:a:b:")) != EOF){
switch( option ){
case 'm': {
flag = flag | 1;
break;
}
case 'a': {
flag = flag | 2;
char * arg = optarg;
aopt = atoi(arg);
if(aopt == 0 && strcmp("0", arg) != 0) // if no valid optarg was entered
aopt = INT_MAX; // get back the default value
break;
}
case 'b': {
flag = flag | 4;
strcpy(bemerkung, optarg);
break;
}
default: {
fprintf(stderr, "Unknown option entered.\n");
return -1;
}
}
}
// some code here, not touching `flag`
if(flag == 1){
// deal with `-m`, no optargs
}
if(flag == 2){
// `-a aopt` called
}
if(flag == 3){
// `-m -a aopt` called
}
The basic idea is to set the bits in flag such that I can handle the options and their combinations later. But the trouble I face right now is that -m requires arguments (should be optional for -m only) and ./main -m -a 0 results into flag = 1 instead of flag = 3.
How do I make arguments for -m optional and get the OR to be done correctly for the flag?
If you want -m to not take any arguments, then omit the : that follows it in the options string. The : means that the preceding option expects an argument:
while((option = getopt (argc, argv, "ma:b:")) != EOF){
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.
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.
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;
}
For some reason, I'm having a hard time trying to cover the block of code below. This code is an excerpt from the UNIX uniq command. I'm trying to write test cases to cover all blocks, but can't seem to reach this block:
if (nfiles == 2)
{
// Generic error routine
}
In context:
int main (int argc, char **argv)
{
int optc = 0;
bool posixly_correct = (getenv ("POSIXLY_CORRECT") != NULL);
int nfiles = 0;
char const *file[2];
file[0] = file[1] = "-";
program_name = argv[0];
skip_chars = 0;
skip_fields = 0;
check_chars = SIZE_MAX;
for (;;)
{
/* Parse an operand with leading "+" as a file after "--" was
seen; or if pedantic and a file was seen; or if not
obsolete. */
if (optc == -1 || (posixly_correct && nfiles != 0) || ((optc = getopt_long (argc, argv, "-0123456789Dcdf:is:uw:", longopts, NULL)) == -1))
{
if (optind == argc)
break;
if (nfiles == 2)
{
// Handle errors
}
file[nfiles++] = argv[optind++];
}
else switch (optc)
{
case 1:
{
unsigned long int size;
if (optarg[0] == '+' && posix2_version () < 200112 && xstrtoul (optarg, NULL, 10, &size, "") == LONGINT_OK && size <= SIZE_MAX)
skip_chars = size;
else if (nfiles == 2)
{
// Handle error
}
else
file[nfiles++] = optarg;
}
break;
}
}
}
Any help would be greatly appreciated. Thanks.
It appears this could be reached when more than 2 files are supplied on the command line. In that case, nfiles would reach the value 2 after the name of the second file has been stored in file[1]. When the code checking nfiles == 2 is reached a third time, then the value will already be 2, and the error handling will execute.
There are two if statements in question. That in switch case "1" can only be reached by using the option in longopts with val == 1.
I just thought I would mention in passing that the automatic generation of test cases to satisfy coverage criteria is transitioning from being a research topic to useful applications. One prototype that I know of is PathCrawler.
The difficulties in the source code that may prevent this or a similar tool to work as hoped are the usual suspects: aliasing and dynamic memory allocation.