Hi there, first post.
I am having a huge issue wrapping my mind around a problem in a program I am currently writing. I need to be able to parse through multiple switches clustered as one command line argument, something like this for example:
-rRsc
I can't use getopt, program_options or any third party libraries or anything like that.
The biggest issue I am facing when I say I cannot wrap my mind around it, is I don't understand how using a simple while loop or switch statement with boolean flags for each switch would be able to account for every conceivable combination of switches. So -rRsc is equal to -rsRc and all other combinations. The only way I've been able to get my program to work so far was with a massive if-else statement over 500 lines just to account for every combination and I know this is wrong. I just can't see how you wouldn't have to do the same thing if the user enters -r and its flagged but what if they enter -rc as this is completely different from just a -r. I need someone to explain how this can be done very simply, preferably with an example as I just can't seem to grasp what seems to be a very easy concept.
Assuming I understand what you're asking, I'd read the data "-rRsc" into a string, then check, say, the first two characters to see that it is a "-r" switch. Then I'd go through character by character, setting booleans or whatever the case may be.
1 2 3 4 5 6 7 8 9
for(unsignedint i = 0; i < op.size(); ++i) { // supposing op has the characters after "-r"
switch(op[i]) {
case'R':
R_flag_set = true; // or whatever R implies
break;
case's':
s_flag_set = true; // or whatever s implies
break;
// and so on
In a way. But what if the s flag is set after the R so now you'd have -rR but what about possible switches afterward? That's the problem, I'm facing. I don't understand how to write efficient and as little code as possible to be able to process all possible combinations
Okay, but what if the switch starts with a character other than -r? I know this must be frustrating to explain, it's just that in the program I am writing different combinations of switches will do different things depending on whats entered. So not only I am trying to determine if every combination can be entered but also how to get my functions to work if certain combinations are entered.
-c (C++ file extensions)
-j (Java file extensions)
-m (Multimedia file extensions)
-x (regex expression for file extensions)
-r (recursive file scan)
-R (reverse alphabetical order of file extensions)
-s (sort by file size)
-h (help)
If these switches are turned on:
1 2 3 4 5 6 7 8
-c will search for .cpp|.c|.h|.hxx|.hpp files
-j will search for .java|.class
-m will search for .avi|.mkv|.mpeg|.mp3|.mp4
-x will allow the user to enter a regex expression (such as "\.(docx|doc)")
-r scans through directories recursively
-R lists files by extension in reverse order (z - a)
-s sorts files by ascending file size OR descending file size if -R is also entered
-h shows how the program is used
Off the top of my head, here's how I'd look at these, in pseudocode:
- By some method, split the command line arguments into strings for each argument (that is, space separated string).
If the user used the argument string "-r -R" then I would have this split into two strings, "-r" and "-R".
If they compressed it to "-rR" I would have that as a single string.
- For each of these strings:
- If the first character is not a '-', note the error on the console and either quit or just ignore that string.
- For each of the remaining characters: (this is the loop I had before)
- If I find 'h', display help and terminate (assuming someone asking for help isn't simultaneously wanting
the program to do any work)
- Otherwise check the character and set the appropriate boolean (practically all of the options are of this kind)
- In the case of 'x', you'd need to check, say, the next string (for a case like "-x <regexp>") or the rest
of the current one (for a case like "-x<regexp>") and store it as your regexp you'll use.
It will be up to you how you'd want to handle someone who inputs something like "-xr <regexp>";
in that case, you may decide to just set a boolean saying to read the next string as a
regexp or something.
Okay so, if flags are set, wouldn't I then after have to if-else through and determine if the flags are set and if in a certain way do this, else do this? Wouldn't that still result in a lot of code for possible combinations?
Depending on how your program is set, you could just have the -c, -j, -m flags populate your regexp variable appropriately (or add to it, depending on how you want them to work).
If you want to save code work for the "reverse order" bit you could define an operator (say, less than) you are going to use to order the results and if you receive a -R just set that operator to the opposite (say, greater than) instead. Then just use that operator in code.
Okay I think I am beginning to understand.
So say a -c, -r and -R flag were set when the user entered -rcR, you'd set the R flag, r flag and the c flag. You would then make an if statement where if those three flags were set you would populate a regex with c++ file extensions, scan recursively for them and print them in reverse order or could you do it in a way without if-elses? Because then you would have to do if-elses in case an -s was used or a -j etc
1 - you can design the switches handler to contain multiple if statements that have no else's.
each if statement calls the proper function, like this:
1 2 3 4 5
if ( (InnerState & FIRST_FLAG) != 0 )
first_handler( /* argument list */ );
if( (InnerState & SECOND_FLAG) !=0 )
second_handler( /* argument list */ );
// . . .
the second approach would be using pointers to functions.
define an array of pointers to functions, initialize it to the switch handling functions.
after you set the Inner-State flags you can put this loop that will call the proper functions:
1 2 3 4 5 6 7 8 9 10 11
// Func is the array of pointers to functions.
constunsignedint NUMBER_OF_FUNCTIONS = 3;
void ( * Func [NUMBER_OF_FUNCTIONS] ) ( /* argument list */ ) = { f1 , f2 , f3 };
//sizeof(Func)/sizeof(Func[0])---->will evaluate to the number of elements in the array.
for( int i=0 ; i < ( sizeof( Func ) / sizeof( Func[0] ) ) ; i++)
{
if( ( InnerState & ( 0x01 << i ) ) != 0 ) // if the i-th flag is set
( * Func[i] ) ( /* argument list */ ); // call the proper function.
}
the down side of this approach is that all functions pointed to by this array MUST have the same argument list and the same return type.