I am working with a simple command line application that takes in ASCI text and interprets it as a command.
I have attempted to minimize the redundancy in this appli
Question:
Is there any method using the C preprocessor that would allow me to create a macro creates the "command" struct (with string and int members), and auto-numbers the int value (command_idx) as I add more commands via the COMMAND() macro?
Yes, and since you have tagged the question also as C++:
#include <iostream>
#include <map>
#include <string>
using namespace std;
map< string, int > commands;
bool register_cmd( int id, string const& name )
{
commands[name] = id;
return true;
}
#define COMMAND( name ) \
int const name ## _cmd = __LINE__; \
bool const name ## _reg = register_cmd( name ## _cmd, #name )
COMMAND( exit );
COMMAND( help );
COMMAND( do_stuff );
int cmd_id( string const& name )
{
auto const it = commands.find( name );
return (it == commands.end()? -1 : it->second );
}
int main()
{
for( auto it = commands.begin(); it != commands.end(); ++it )
{
cout << it->first << " => " << it->second << endl;
}
cout << "Gimme a command, please: ";
string cmd; getline( cin, cmd );
switch( cmd_id( cmd ) )
{
case exit_cmd:
cout << "You typed an EXIT command, which has id " << exit_cmd << endl;
break;
default:
cout << "Hey, why not try an 'exit' command?" << endl;
}
}
I just used map
instead of fancy new C++11 hash table because map
works with older compilers and no real need for shaving nano-seconds here.
Cheers & hth.,
You can use macro redefinition to achieve this. First, you create a file that simply lists your commands called commands.inc
:
COMMAND(quit)
COMMAND(help)
...
Then, in your C source you can #include "commands.inc"
multiple times, with different definitions of COMMAND()
in effect to control how it works. For example:
struct command
{
char *name;
int command_idx;
};
#define COMMAND(NAME) CMD_ ## NAME,
enum command_enum {
#include "commands.inc"
};
#undef COMMAND
#define COMMAND(NAME) { #NAME, CMD_ ## NAME },
struct command commands[] =
{
#include "commands.inc"
};
#undef COMMAND
(Note that this particular example relies on a C99 improvement that allows a trailing ,
at the end of the lists in the enum
declaration and compound initialiser - you can easily work around that in C89 by adding a dummy entry at the end).