Not so long ago, at work, I faced the task of writing a program in the C ++ Builder environment, and there was a moment in it when I needed to parse the command line. The task also included the magic “you can use all the sources that are there. They lie here: ... ". The first thing I did, of course, was to the address ... and I found there a terribly branching code structure in which I tried to figure it out and decided that it was hell to customize it for myself. Therefore, it occurred to me to write something like Qt-shnoy system of signals and slots, only for C ++ Builder and command line arguments.
So, let's begin. The idea is as follows: analysis of the command line is reduced to checking whether there is a special character in the argument (in my case, this “-” - was to take the Linux standard). Depending on this, the argument is read as the parameter name or its value. To call processing functions, an associative array is used, i.e. an array in which the keys are the names of the available parameters, and the values ​​are the addresses of the processing functions of a particular parameter. Here, in general, and all. Getting to the implementation?
Forward. Let's start with the study of devices. To handle associative arrays in C ++ Builder, the map type is used (declared in map.h)
#include <map.h>
Further on help. Declare your type:
')
typedef map <AnsiString, int*> TFuncTable;
and in the class instance type:
TFuncTable funcTable;
Here, AnsiString is used as the key (forgive me std :: string), and the values ​​are int * (by the way, it may not work for 64-bit systems). Now, let's see how to insert into this hash. It turned out that it was not so easy and it had to kill 2 hours. And this is done like this:
int *addr = (int*)&myFunction;
funcTable.insert(TFuncTable::value_type(AnsiString("-myParam"), addr));
It is worth paying attention to TFuncTable :: value_type () - why do this, I honestly did not understand, but apparently this is some kind of type fitting, without which the program does not even compile.
So, initialized the array - great. What will it look like? Yes, something like this:
funcTable[“-myParam”] == 0xABCDEF // -
Slowly but surely, we approach the use of this whole economy. Immediately it is worth mentioning one minus of such an algorithm: processing functions must be of the same type, that is, we declare a functional type:
typedef void (*TFunc)(AnsiString param);
and stick to it in writing your handlers. An example of such a handler:
void myFunction(AnsiString name)
{
MainForm->setTestName(name);
}
But this is a simple handler. It will be more difficult, perhaps, when something like comes in as a parameter:
"param1,param2,param3"
For a real example, you can look at the / etc / fstab file - Linux.
Well, it's time to tell how to start the function from the hash by the parameter name. Yes, but before that, I think it is worth collecting the entire initialization procedure in a heap:
- Enable map
- Declared a type hash, declared an instance of this type.
- Declared a functional type and wrote function-parameter handlers, adhering to this type.
- Fill the hash.
Now you can proceed to the processing function of the command line itself. Here is the algorithm for calculating whether the argument is a parameter name or its value:
bool TMainForm::parseParams()
{
int argc;
TFunc srvFunc;
LPWSTR *cmdLine = CommandLineToArgvW(GetCommandLineW(), &argc);
int iter = 1;
for(int i = 1; i < argc; i += iter)
{
AnsiString param = "";
AnsiString paramName = cmdLine[i];
if(i < argc - 1)
{
if(AnsiString(cmdLine[i + 1])[1] == '-')
iter = 1;
else
{
param = cmdLine[i + 1];
iter = 2;
}
}
if(funcTable.find(paramName) == funcTable.end())
{
Out(" " + paramName);
return false;
}
srvFunc = (TFunc)funcTable[paramName];
srvFunc(param);
}
return true;
}
What is what:
LPWSTR * cmdLine = CommandLineToArgvW (GetCommandLineW (), & argc); - with this in the Borlandovsky certificate, too, everything is rather dull, but it all boils down to the fact that such a sequence of transformations produces standard argc and argv, so we go further.
Out () is a specialized input / output function. For a given topic does not represent any interest.
I don’t need to tell the procedure for searching for the “-” character in the string argument - it’s banal. The most interesting here:
srvFunc = (TFunc)funcTable[paramName];
srvFunc(param);
This is how the handler function starts. Simple, isn't it? And no wild branching up to the 1000th knee.
So what do we have? I work in the state. office, and that's why linger there not going. That is, the worker who came after me will easily write his handlers, will drive addresses into the hash, and he will not have to think about the command line analyzer. Here is the arithmetic.