Commandline argh [sic] processing

P

pemo

Opinion please.

The code below is an attempt at demonstrating commandline arg processing.

I don't really like the repetitive use of ...

if(!(*s))
{
// Make sure we don't go out of bounds.
//
p = i + 1 >= argc ? NULL : argv[++i];
}

and, of course, I'm not sure the code is either 'sound' or optimal for what
it does.

Feedback welcome.


#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>


#define trace(...) printf(__VA_ARGS__)



void usage(void);

// Tested with [as noise and signal]
//
// -f test.c -a -B --n 10 -ftest1 -n50 - f three -k
//
// as args.



int main(int argc, char * argv[])
{
// Holds the switch char, e.g., given -f, this will be 'f' when it
matters.
//
char c = 0;

// Used to point at an argv.
//
char * s = NULL;
char * p = NULL;

// A buffer for the -f switch implementation to use.
//
char buffer[100];

// A number for the -n switch implementation to use.
int num = 0;

// Loop counter for argc handling.
//
int i = 0;

// If we've no useful args, tell the user [will exit].
//
if(argc <= 1)
{
usage();
}

// For each arg ...
//
for(i = 1; i < argc; ++i)
{
s = argv;

p = NULL;

// If this argv is a valid switch? The first char needs to be a /
or a -,
// and the following part must contain one of the chars we
expect. The
// leading @ in the test string is important as it's acting as a
'guard'..
// we don't want to return 0 if we find a valid char basically, so
[0] has
// a character we shouldn't find.
//
if((*s == '/' || *s == '-') && strcspn("@abfnABFN", ++s))
{
// For each char after the / or - .... !p is there because if
the
// 'meat' of the switch directly follows the flag character,
this
// while loop will iterate through the non-switch-char
characters.
//
while((c = *s++) && !p)
{
switch(toupper(c))
{
case '?':

usage();

break;


case 'A':

trace("-A switch found\n");

break;


case 'B':

trace("-B switch found\n");

break;


case 'F': // -f indicates there's a string
parameter coming.

trace("-F switch found\n");

{
// If there's a '\0' following 'F', then the
string
// we're wanting should be in the next argv as
this
// argv is terminated.
//
if(!(*s))
{
// Make sure we don't go out of bounds.
//
p = i + 1 >= argc ? NULL : argv[++i];
}

// No terminator, so the filename is flush up
against the -f - or was not given!
//
else

{
p = s;
}

if(!p)
{
fprintf(stderr, "\t-F: but no filename
found!\n");
}

else

{
strncpy(buffer, p, sizeof(buffer));

trace("\tfilename: %s\n", buffer);
}
}
break;

case 'N': // -n indicates there's a numeric
parameter coming [expected].

trace("-N switch found\n");

{
if(!(*s))
{
p = i + 1 >= argc ? NULL : argv[++i];
}

else

{
p = s;
}

if(!p)
{
fprintf(stderr, "\t-N: but no integer
found!\n");
}

else

{
sscanf(p, "%d", &num);

trace("\tvalue: %d\n", num);
}
}
break;

default:

trace("\nShouldn't get here ... unknown or badly
formatted flag!: argv[%d] = '%s'\n\n", i, argv);

break;
}
}
}
else
{
trace("\n\tOther params ... input file etc?: %s\n\n", s);
}
}

getchar();

return EXIT_SUCCESS;
}


void usage(void)
{
puts("Usage:\n\n");
puts("\t-a, -b : test switches");
puts("\t-f<filename> : test switch with a string parameter");
puts("\t-n<num> : test switch with a numeric parameter");

exit(0);
}
 
B

Ben Pfaff

pemo said:
The code below is an attempt at demonstrating commandline arg processing.

I don't really like the repetitive use of ...

if(!(*s))
{
// Make sure we don't go out of bounds.
//
p = i + 1 >= argc ? NULL : argv[++i];
}

I would suggest writing a helper function or two. There are
many, *many* libraries and examples out there for helping out
with command-line processing. I'm sure you can find one you
like.
 
R

Rod Pemberton

pemo said:
Opinion please.

The code below is an attempt at demonstrating commandline arg processing.

I don't really like the repetitive use of ...

if(!(*s))
{
// Make sure we don't go out of bounds.
//
p = i + 1 >= argc ? NULL : argv[++i];
}

You are reinventing getopt. But, that's okay. I've done it myself.

I'd suggest the following:

1) using argv[j] will save some grief over using s & p
2) loop from 0 to argc, determine which argv's are flag args using strstr
and/or strspn, storing the results in an flag indicator array and requoting
args if necessary
3) loop from 0 to argc, if flag array indicates arg is a flag, switch to
appropriate setup routine ( At this point, I usually setup a control array
where a value representing the selected option indexes into the control
array returning the correct argv position. The control array can then be
selectively used throughout your program to include or exclude code and you
have access to the correct argv values immediately.)


Rod Pemberton
 
A

Arndt Jonasson

Rod Pemberton said:
pemo said:
Opinion please.

The code below is an attempt at demonstrating commandline arg processing.

I don't really like the repetitive use of ...

if(!(*s))
{
// Make sure we don't go out of bounds.
//
p = i + 1 >= argc ? NULL : argv[++i];
}

You are reinventing getopt. But, that's okay. I've done it myself.

I'd suggest the following:

1) using argv[j] will save some grief over using s & p
2) loop from 0 to argc, determine which argv's are flag args using strstr
and/or strspn, storing the results in an flag indicator array and requoting
args if necessary
3) loop from 0 to argc, if flag array indicates arg is a flag, switch to
appropriate setup routine ( At this point, I usually setup a control array
where a value representing the selected option indexes into the control
array returning the correct argv position. The control array can then be
selectively used throughout your program to include or exclude code and you
have access to the correct argv values immediately.)


One can also use the fact that argv[argc] is a NULL pointer.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

No members online now.

Forum statistics

Threads
474,176
Messages
2,570,947
Members
47,498
Latest member
log5Sshell/alfa5

Latest Threads

Top