The Clixon CLI uses CLIgen best described by the CLIgen tutorial. The example is also helpful.
Clixon adds some features and structure to CLIgen which include:
-
A plugin framework for both textual CLI specifications(.cli) and object files (.so)
-
Object files contains compiled C functions referenced by callbacks in the CLI specification. For example, in the cli spec command:
a,fn()
,fn
must exist oin the object file as a C function.- A CLI API struct is given in the plugin. See example.
-
A CLI specification file is enhanced with the following CLIgen variables:
CLICON_MODE
: A colon-separated list of CLIgenmodes
. The CLI spec in the file are added to all modes specified in the list.CLICON_PROMPT
: A string describing the CLI prompt using a very simple format with:%H
,%U
and%T
.CLICON_PLUGIN
: the name of the object file containing callbacks in this file.
-
Clixon generates a command syntax from the Yang specification that can be refernced as
@datamodel
. This is useful if you do not want to hand-craft CLI syntax for configuration syntax. Example:set @datamodel, cli_set(); merge @datamodel, cli_merge(); create @datamodel, cli_create(); show @datamodel, cli_show_auto("running", "xml");
The commands (eg
cli_set
) will be called with the first argument an api-path to the referenced object. -
The CLIgen
treename
syntax does not work.
Clixon CLI supports persistent command history. There are two CLI history related configuration options: CLICON_CLI_HIST_FILE
with default value ~/.clixon_cli_history
and CLICON_CLI_HIST_SIZE
with default value 300.
The design is similar to bash history but is simpler in some respects:
- The CLI loads/saves its complete history to a file on entry and exit, respectively
- The size (number of lines) of the file is the same as the history in memory
- Only the latest session dumping its history will survive (bash merges multiple session history).
Further, tilde-expansion is supported and if history files are not found or lack appropriate access will not cause an exit but will be logged at debug level
CLIgen is designed to handle large specifications in runtime, but it may be difficult to handle large specifications from a design perspective.
Here are some techniques and hints on how to reduce the complexity of large CLI specs:
The CLICON_MODE
can be used to add the same syntax in multiple modes. For example, if you have major modes configure
and operation
and a set of commands that should be in both, you can add a sub-mode that will appear in both configure and operation mode.
CLICON_MODE="configure:operation";
show("Show") routing("routing");
Note that CLI command trees are merged so that show commands in other files are shown together. Thus, for example:
CLICON_MODE="operation:files";
show("Show") files("files");
will result in both commands in the operation mode (not the others):
cli> show <TAB>
routing files
You can also use sub-trees and the the tree operator @
. Every mode gets assigned a tree which can be referenced as @name
. This tree can be either on the top-level or as a sub-tree. For example, create a specific sub-tree that is used as sub-trees in other modes:
CLICON_MODE="subtree";
subcommand{
a, a();
b, b();
}
then access that subtree from other modes:
CLICON_MODE="configure";
main @subtree;
other @subtree,c();
The configure mode will now use the same subtree in two different commands. Additionally, in the other
command, the callbacks will be overwritten by c
. That is, if other a
, or other b
is called, callback function c
will be invoked.
You can also add the C preprocessor as a first step. You can then define macros, include files, etc. Here is an example of a Makefile using cpp:
C_CPP = clispec_example1.cpp clispec_example2.cpp
C_CLI = $(C_CPP:.cpp=.cli
CLIS = $(C_CLI)
all: $(CLIS)
%.cli : %.cpp
$(CPP) -P -x assembler-with-cpp $(INCLUDES) -o $@ $<