Here we'll cover all the steps to create your own CLI application.
In order to do that, we will show all the steps to create one of the examples provided by the library.
Specifically, we will refer to examples/nettool/.
Bare in mind this example has not to be considered as a real-life application (all callbacks just call Linux shell commands), while its aim is just to show you what CLIck does for you.
First file to edit is the CLI definition XML file.
In order to do that we need to define:
Please remember that entering a new context will require a specific command, so every new context is always under a command.
Here follows the content of the structure file of nettool sample application..
<context> <prompt>main</prompt> <command> <name>shell</name> <brief>"runs the OS shell"</brief> <help>"Executes the SHELL command to run user default shell application"</help> <function>shell_cbk</function> </command> <command> <name>info</name> <brief>"gives some basic System info"</brief> <help>"Prints basic system and setup information"</help> <function>info_cbk</function> <param> <name>name</name> <required>true</required> <numval>2</numval> <reqval>false</reqval> </param> <command> <name>all</name> <brief>"gives additional System info"</brief> <help>"Prints system and setup information, including kernel that is being used"</help> <function>info_all_cbk</function> </command> </command> <command> <name>credits</name> <brief>"info on this program"</brief> <help>"Type this if you want to know something more about the author"</help> <function>credits_cbk</function> </command> <command> <name>config</name> <brief>"enters the configuration context"</brief> <help>"Type this command to test multi-context"</help> <function>config_cbk</function> <context> <prompt>config</prompt> <command> <name>user</name> <brief>"configures user properties"</brief> <help>"This command configures user properties"</help> <function>config_user_cbk</function> </command> <command> <name>net</name> <brief>"command to configure network"</brief> <help>"This command is used to configure network interfaces"</help> <function>config_net_cbk</function> <command> <name>ip</name> <brief>"command to configure network IP address"</brief> <help>"This command is used to configure network IP address"</help> <function>config_net_ip_cbk</function> </command> <command> <name>interface</name> <brief>"sets the network interface to work on"</brief> <help>"This command is used to set network interface that will be used by all net commands"</help> <function>config_net_interface_cbk</function> <context> <prompt>interface</prompt> <command> <name>up</name> <brief>"brings UP the interface"</brief> <help>"This command enables the network interface"</help> <function>config_interface_up_cbk</function> </command> <command> <name>down</name> <brief>"puts DOWN the interface"</brief> <help>"This command disables the network interface"</help> <function>config_interface_down_cbk</function> </command> </context> </command> <command> <name>mask</name> <brief>"command to configure network IP nextmask"</brief> <help>"This command is used to configure network IP netmask"</help> <function>config_net_mask_cbk</function> </command> </command> </context> </command> </context>
General usage of clickbuilder is:
my-linux-box$ clickbuilder <cli_structure_file> <output_prefix>
clickbuilder will then generates two files:
As per our example:
my-linux-box$ clickbuilder nettool.xml nettool
This will create:
As a general rule, we suggest to put implementation of callbacks that are supposed to be called when a command is matching in one or more dedicated .c file(s).
Doing so, it will be easy to get quickly to the callback implementation.
As a useful reference, file <output_filename_prefix>.h will contain all the prototypes of the functions you need to implement. Suggestion is to keep a separae file for callbacks implementation, especially making sure that automatically-generated files are NEVER manually modified, otherwise everytime a modification to the CLI structure is needed, those files will be overwritten.
According to our example, please refer to file nettool_cbk.c file in examples/nettool/ directory
Once the code has been generated, the function click_main() allows you to run a new CLI instance. click_main() requires a pointer to the main context as parameter. You can easily get it via the helper function getmaincontext_<output_prefix>() will be defined in <output_prefix>.h, and implemented in <output_prefix>.c.
int click_main(const FILE *in, const FILE *out, Clicontext *maincontext);
in and out indicate the input and output streams, useful in case of redirection to sockets, regular files, etc. In most normal situations, the user intention is just to use regular terminal I/O, and so you just need to pass ANSI C macros stdin and stdout.
At this point in time, you need to call this function in your own code in order to enter the CLI.
For sake of simplicity, since our example application does nothing but entering the CLI, the CLI entry point will be directly called by application main() function. File nettool_main.c contains the main() function, that doesn't do anything but calling the CLI entrypoint:
int main() { return click_main(stdin,stdout,getmaincontext_nettool()); }
All the symbols contained in the mentioned C files are needed to link the final application.
Linking a CLIck application will also require:
So, referring again to the provided example, we are going to compile, assembly and link everything in one single command:
my-linux-box$ cc -o nettool nettool.c nettool_cbk.c nettool_main.c -lclick -lm
This will generate nettool application, dynamically linked to click library.
Now you are ready to run your application