Back to home
page
Back to previous
page
Introduction
Download
Installation
Packaging
API
About the author
Related links
Introduction
cmdline is a
command line
manager API much more simple and light than GNU readline. It does
not use any database or configuration files like terminfo, termcap and
so on... It is destined to command line oriented programs.
The
API manages the command line and all the related goodies such
as
the line edition, the history of commands, the function keys and the
character echoing.
The keys which are managed by the service are emacs-like:
Move the cursor one char
forward
Same as CTRL f
Move the cursor one char
backward
Same as CTRL b
Move the cursor to the end
of line
Move the cursor to the
beginning of line
Same as CTRL a
Same as CTRL e
Remove the character on
which the cursor is
Same as SUPPR.
But when the command line is empty, it triggers a "End Of File" on the
input.
Remove the character on
the left side of the cursor
Display the previous
command line of the history (i.e. go up in the history)
Display the following
command line of the history (i.e. go down in the history)
Display the oldest command
line of the history
Display the newest command
line of the history
Triggers
the auto-completion or displays
spaces depending on the way the CMDLINE object has been
initialized.
Download
CMDLINE can be downloaded from this page
in one of the following three ways:
- Source package (tgz: tar compressed file)
- DEB binary package
- RPM binary
package
The include
directory contains the file cmdline.h
in which are defined the services
and data structures of the API.
The lib
directory contains the implementation of the library libcmdline.so
which
is destined to be dynamically linked to the user program.
The man
directory contains the on-line manuals.
Installation
Installation
from the sources with cmake
The installation from the sources supposes that cmake
is installed on your Linux machine.
Unpack the tar compressed file cmdline-xxx.tgz
into a directory. This will create a sub-directory called cmdline-xxx with
the
source files of the program:
$ tar xvfz
cmdline-xxx.tgz
Go into the newly created directory:
$ cd cmdline-xxx
While building the makefiles, you can choose where the files will be
installed with the environment variable CMAKE_INSTALL_PREFIX.
If not defined, the installation defaults to /usr/local.
$ cmake .
-DCMAKE_INSTALL_PREFIX=<path_of_installation>
Then the build is triggered by invoking make:
$ make
And the installation is done specifying the install target:
$ make install
It is possible to trigger a cleanup of the built objects
with the clean
target:
$ make clean
If your MANPATH
variable is correctly set, CMDLINE's online manual can be displayed:
$ man 3 cmdline
Installation
from the sources with a custom script
The installation from the sources supposes that cmake
is installed on your Linux machine.
Unpack the tar compressed file cmdline-xxx.tgz
into a directory. This will create a sub-directory called cmdline-xxx with
the
source files of the program:
$ tar xvfz
cmdline-xxx.tgz
Go into the newly created directory:
$ cd cmdline-xxx
Make sure the file cmdline_install.sh
has the execute permission:
$ chmod +x
cmdline_install.sh
Launch the script
cmdline_install.sh
to get the help:
$
./cmdline_install.sh
-h
Usage:
cmdline_install.sh [-d install_root_dir] [-P DEB | RPM] [-B] [-I] [-A]
[-h]
-d
:
Installation
directory
(default: /usr/local)
-P
:
Generate
a
DEB or RPM package
-B
:
Build
the
software
-I
:
Install
the
software
-A
:
Generate
an
archive of the software (sources)
-h
:
this
help
Under root identity, launch the installation by passing '-I' and
optionnaly '-d' to specify an installation directory different
than /usr/local.
For example, for an installation in /usr/local, type:
$ sudo
./cmdline_install.sh -I
For an installation in '/usr', type;
$ sudo
./cmdline_install.sh -I -d /usr
If your MANPATH
variable is correctly set, CMDLINE's online manual can be displayed:
$ man 3 cmdline
Installation
from the DEB binary package
The files are installed via the command:
$ sudo dpkg -i
cmdline-xxx.deb
Installation
from the RPM binary package
The files are installed via the command:
$ sudo rpm -i
cmdline-xxx.rpm
Packaging
The packaging process supposes that cmake
is installed on your Linux machine.
Generation
of a DEB binary package
Unpack the tar compressed file cmdline-xxx.tgz
into a directory. This will create a sub-directory called cmdline-xxx with
the
source files of the program:
$ tar xvfz
cmdline-xxx.tgz
Go into the newly created directory:
$ cd cmdline-xxx
Make sure the file cmdline_install.sh
has the execute permission:
$ chmod +x
cmdline_install.sh
Launch the script cmdline_install.sh
to get the help:
$
./cmdline_install.sh
-h
Usage:
cmdline_install.sh [-d install_root_dir] [-P DEB | RPM] [-B] [-I] [-A]
[-h]
-d
:
Installation
directory
(default: /usr/local)
-P
:
Generate
a
DEB or RPM package
-B
:
Build
the
software
-I
:
Install
the
software
-A
:
Generate
an
archive of the software (sources)
-h
:
this
help
Under root identity, launch the installation by passing '-P DEB' and
optionnaly '-d' to specify an installation directory different
than /usr/local.
For example, for a package which will be installed in /usr/local, type:
$ sudo
./cmdline_install.sh -P DEB
For an installation in /usr,
type;
$ sudo
./cmdline_install.sh -P DEB -d /usr
Generation
of a RPM binary package
Unpack the tar compressed file cmdline-xxx.tgz
into a directory. This will create a sub-directory called cmdline-xxx with
the
source files of the program:
$ tar xvfz
cmdline-xxx.tgz
Go into the newly created directory:
$ cd cmdline-xxx
Make sure the file cmdline_install.sh
has the execute permission:
$ chmod +x
cmdline_install.sh
Launch the script cmdline_install.sh
to get the help:
$
./cmdline_install.sh
-h
Usage:
cmdline_install.sh [-d install_root_dir] [-P DEB | RPM] [-B] [-I] [-A]
[-h]
-d
:
Installation
directory
(default: /usr/local)
-P
:
Generate
a
DEB or RPM package
-B
:
Build
the
software
-I
:
Install
the
software
-A
:
Generate
an
archive of the software (sources)
-h
:
this
help
Under root identity, launch the installation by passing '-P RPM' and
optionnaly '-d' to specify an installation directory different
than /usr/local.
For example, for a package which will be installed in /usr/local, type:
$ sudo
./cmdline_install.sh -P RPM
For an installation in /usr,
type;
$ sudo
./cmdline_install.sh -P RPM -d /usr
Generation
of a ZIP tar file
Unpack the tar compressed file cmdline-xxx.tgz
into a directory. This will create a sub-directory called cmdline-xxx with
the
source files of the program:
$ tar xvfz
cmdline-xxx.tgz
Go into the newly created directory:
$ cd cmdline-xxx
Make sure the file cmdline_install.sh
has the execute permission:
$ chmod +x
cmdline_install.sh
Launch the script cmdline_install.sh
to get the help:
$
./cmdline_install.sh
-h
Usage:
cmdline_install.sh [-d install_root_dir] [-P DEB | RPM] [-B] [-I] [-A]
[-h]
-d
:
Installation
directory
(default: /usr/local)
-P
:
Generate
a
DEB or RPM package
-B
:
Build
the
software
-I
:
Install
the
software
-A
:
Generate
an
archive of the software (sources)
-h
:
this
help
Under root identity, launch the installation by passing '-A':
$ sudo
./cmdline_install.sh -A
API
Services
The API is composed with the following functions:
#include
<cmdline.h>
roof_ctx_t *cmdline_new(cmdline_param_t
*param);
void cmdline_delete(cmdline_t
*pInst);
char *cmdline_interact(cmdline_t *pInst);
int cmdline_split(unsigned char *str,
unsigned int *ac, unsigned char ***av, unsigned char comment);
int cmdline_set_debug_level(cmdline_t *pInst, int dbg);
int cmdline_set_echo(cmdline_t *pInst, int echo);
int cmdline_set_histo(cmdline_t
*pInst,
int histo);
void cmdline_histo_list(cmdline_t
*pInst, void (* list)(unsigned char *item, unsigned int idx));
char *cmdline_histo_get(cmdline_t
*pInst,
unsigned
int
idx);
cmdline_fn_key_t cmdline_function_key(cmdline_t
*pInst, cmdline_fn_key_t function_key);
int cmdline_restore_term_settings(cmdline_t
*pInst);
int cmdline_set_term_settings(cmdline_t
*pInst);
cmdline_new
The service cmdline_new()
creates a CMDLINE object. This is a handle that will
be
passed to all the subsequent calls to the API through the
parameter pInst. The configuration of CMDLINE is passed
through
the parameter param
of type cmdline_param_t:
typedef
struct
{
//
---
Command
line
unsigned
int
line_len;
//
Maximum
length
of the command line
//
---
I/O
int
non_blocking;
//
!0,
if
I/O in non blocking mode
int
fd_in;
//
Input
file
descriptor
int
fd_out;
//
Output
file
descriptor
//
---
History
unsigned
int
histo_len;
//
History
size
int
auto_or_sp;
//
Auto-completion
or
spaces
for TAB
#define
CMDLINE_TAB_AUTO_COMPLETE
0
//
Provide
’auto_complete’
callback (may be NUL)
#define
CMDLINE_TAB_SPACES
1
//
Provide
the
number of ’spaces’ for a TAB (may be 0)
union
{
void
(*auto_complete)
//
Callback
called
upon
TAB keystroke to trigger auto-completion
(
void
*ctx,
//
User
context
const
char
*cmd_line,
//
Current
displayed
command
line
unsigned
int
*cursor,
//
IN:
Current
cursor
position
//
OUT:
New
cursor
position
char
**completed_cmd_line
//
New
command
line if any (NULL otherwise)
);
unsigned
int
spaces;
//
Number
of
spaces
to display for a TAB
}
tab;
char
histo_shortcut;
//
Character
to
call an history entry (0 if not
activated)
void
*ctx;
//
Any
user
provate
information for future reference
}
cmdline_param_t;
line_len
specifies the maximum size
in bytes of the command line to manage.
non_blocking
is
set to 0 if the interactions on the input
are
blocking. This means that the service cmdline_interact() will block the
caller until a command line is available. If non_blocking
is set to a value different than 0, the service cmdline_interact()
returns NULL with errno set to
EAGAIN if data are not available on the input. The
command line will be available only when the cmdline_interact() will
return a value different than NULL. This mode is
useful when the caller needs to manage interactions with
multiple file descriptors (e.g. sockect connections, data from
terminals, data from pipes...). It will typically invoke the
system call select() to be warned when data are made
available on some file descriptors. Then, if one of the concerned file
descriptors is managed by a CMDLINE object,
cmdline_interact() is called to get the data.
fd_in
is the file descriptor of
the input from which we get the command lines.
fd_out
is the file descriptor of
the output to which are echoed the command lines.
histo_len
specifies the number of recorded command lines in the history of
commands.
auto_or_sp
specifies
the significant field in the tab union. If set to
CMDLINE_TAB_AUTO_COMPLETE, the caller will need to provide a callback
function that will be called upon TAB keystroke. The
field ctx
is passed back to the callback as first
parameter.
The callback may be set to NULL if the auto-completion is not
required. If set to CMDLINE_TAB_SPACES, the caller
will
need to specify the number of space
characters that
will be output upon TAB keystroke. It can be set to 0, if TAB key is to
be ignored.
histo_shortcut
specifies
the character that will trigger the call to an history entry. Each time
this character will appear at first position on the command
line,
it will trigger a call to the history entry associated to the index.
The index is the following numeric value.
ctx
can
be set to any value. It is passed back to the history
callback.
Typically, this field embeds the address of a user
context.
cmdline_delete
The service cmdline_delete()
is the counter part of cmdline_new()
as it deallocates a CMDLINE object previously allocated by cmdline_new().
cmdline_interact
The service cmdline_interact()
reads a command line on the input managing implicitely the line
edition and the history.
The function is
either blocking or non blocking depending on the parameter non_blocking
passed to cmdline_new().
The returned buffer is either a pointer on a NUL terminated string
inside the service (there is no end of line at the end of the buffer)
or a control message.
The maximum length of the returned buffer is the size of the line
configured with the field line_len
in the structure cmdline_param_t
passed to cmdline_new().
The control message begins with two bytes: CMDLINE_CTRL_MSG followed the number
of bytes composing the message (i.e. at most 255) and the bytes of the
message. The format is described below:
Byte
1
2
3...
+----------------+------+-------------------
|CMDLINE_CTRL_MSG|Lenght|
...Length
bytes...
+----------------+------+-------------------
This is convenient for applications needing to exchange control
messages inside the character stream.
To know if it is a line of characters or a control message, the user
must check the first byte of the returned buffer: if it is a CMDLINE_CTRL_MSG, then it is a
control message otherwise it is a NUL terminated line of characters.
The buffer's content stays available until the next call to cmdline_interact().
cmdline_split
The service cmdline_split()
splits a command line str
into words pointed by av.
The
latter
is
dynamically allocated and so should be deallocated by the
caller when no longer needed. The latest entry is set to NULL. The number
of non NULL entries in av is stored into ac. On input, the
caller has the ability to pass a preallocated buffer from the heap by
setting av with the
address of the buffer and ac
with the number of entries minus one in this buffer. The service will
enlarge the buffer if necessary. The caller has the ability to
specify in comment
the character which is used as comment: all the characters from this
character up to the end of the line are ignored. Setting this
parameter to 0 (i.e. '\0') specifies that comments are not
managed. After this call, the passed command line str is altered.
cmdline_set_debug_level
The service cmdline_set_debug_level()
sets the debug level to dbg.
The
more
dbg
is big, the more traces will appear. The
value 0 cancels the debug mode. dbg must be
greater or equal to 0.
cmdline_set_echo
The service cmdline_set_echo()
activates (parameter echo
greater than 0) or deactivates
(parameter echo
equal to 0) the echo of the input characters.
cmdline_set_histo
The service cmdline_set_histo()
activates
(parameter
histo
greater than 0) or deactivates (parameter histo equal
to 0) the history.
cmdline_histo_list
The service cmdline_histo_list()
lists all the entries currently present in the
history. For
each entry, the callback list is invoked. It is passed the history
entry along with its index. The end of list is denoted when the
parameters passed to the callback are NULL.
cmdline_histo_get
The service cmdline_histo_get()
returns the history entry associated to the index idx.
cmdline_function_key
The function cmdline_function_key()
sets the callback function_key
to be invoked when a function key is pressed. The callback
type is:
typedef
const
char
*
(* cmdline_fn_key_t)
(
cmdline_t
*pInst,
unsigned
int
fn,
const
char
*cmd_line,
unsigned
int
*cursor
);
The
callback is passed the
parameter fn
which contains the function key
number
CMDLINE_FUNC_KEY_1 to CMDLINE_FUNC_KEY_12, the current command line and
the current cursor position in the command line. The callback
returns the new command line to display (NULL if nothing to do) and the
new cursor position.
cmdline_restore_term_settings
The service cmdline_restore_term_settings()
sets back the terminal settings to the
values which were set before the call to cmdline_new().
This
service
is
typically
used in conjunction with cmdline_set_term_settings()
when the program needs to fork and execute a new
program. The service is typically called before forking to
avoid the inheritance of the CMDLINE terminal settings by the child
process.
cmdline_set_term_settings
The service cmdline_set_term_settings()
sets the terminal settings to the values
requested upon the call to cmdline_new().
This
service
is
typically
used in conjunction with cmdline_restore_term_settings()
when the program needs to fork and execute a new
program. The service is typically called after the termination of
the child process.
Return value
Example
The following example shows a
complete application using the API in blocking mode:
#define _GNU_SOURCE
#include <getopt.h>
#include <unistd.h>
#include <stdio.h>
#include <libgen.h>
#include <errno.h>
#include <string.h>
#include <strings.h>
#include <sys/select.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <cmdline.h>
//
----------------------------------------------------------------------------
// Name : cmdline_prompt
// Usage : Prompt on the command line
//
----------------------------------------------------------------------------
static
const char *cmdline_prompt = "$$";
//
----------------------------------------------------------------------------
// Name : cmdline_inst
// Usage : CMDLINE instance
//
----------------------------------------------------------------------------
static cmdline_t *cmdline_inst;
//
----------------------------------------------------------------------------
// Name : cmdline_longops
// Usage : Option on the command line
//
----------------------------------------------------------------------------
static struct option cmdline_longopts[] =
{
{ "debug",
required_argument, NULL, 'd' },
{
"help",
no_argument,
NULL, 'h' },
// Last entry
{
NULL,
0,
NULL,
0
}
};
//---------------------------------------------------------------------------
// Name : cmdline_help
// Usage: Display help
//----------------------------------------------------------------------------
static void cmdline_help(char *p)
{
fprintf(stderr,
"\n"
"Usage: %s [<options> ...]\n"
"\n"
"Options:\n"
"\n"
"\t-d | --debug level : Set debug mode to level\n"
"\t-h |
--help
: This help\n"
,
basename(p)
);
} // cmdline_help
//----------------------------------------------------------------------------
//
Name
: cmdline_is_number
// Description : Check if a string is a number
// Return : 1, if yes
//
0,
if
not
//----------------------------------------------------------------------------
static int cmdline_is_number(const unsigned char *str)
{
while (*str)
{
if (!isdigit(*str))
{
return 0;
}
str ++;
}
return 1;
} // cmdline_is_number
static void disp_histo_item
(
unsigned
char
*item,
unsigned
int
idx
)
{
if (item)
{
printf("%u. %s\n", idx, item);
}
} // disp_histo_item
//---------------------------------------------------------------------------
// Name : function_key
// Usage: Callback for the function key
//----------------------------------------------------------------------------
static const unsigned char *function_key(
cmdline_t
*pInst,
unsigned
int
fn,
const
unsigned
char
*cmd_line,
unsigned
int
*cursor
)
{
char buf[128];
(void)cmd_line;
(void)pInst;
snprintf(buf, sizeof(buf), "\nFunction key %u has been pressed (cursor
pos = %u)\n%s ", fn + 1, *cursor, cmdline_prompt);
buf[sizeof(buf) - 1] = '\0';
write(1, buf, strlen(buf));
// New cursor position
*cursor = 4;
return (const unsigned char *)"New cmd_line";
} // function_key
//---------------------------------------------------------------------------
// Name : main
// Usage: Entry point of the program
//----------------------------------------------------------------------------
int main(int ac, char *av[])
{
unsigned int options;
int
opt;
int
rc;
int
dbg
=
0;
cmdline_param_t params;
unsigned char *p;
options = 0;
// Parse the command line
optind = 0;
while ((opt = getopt_long(ac, av, "d:h", cmdline_longopts, NULL)) !=
EOF)
{
switch(opt)
{
case 'd' : // Debug level
{
if
(!cmdline_is_number((unsigned char *)optarg))
{
fprintf(stderr, "The debug level must be a number instead of '%s'\n",
optarg);
rc = 1;
goto error;
}
dbg = atoi(optarg);
options |= 0x01;
}
break;
case 'h' : // Help
{
cmdline_help(av[0]);
options |= 0x02;
exit(0);
}
break;
case '?' :
default :
{
cmdline_help(av[0]);
exit(1);
}
} // End switch
} // End while
// Get a CMDLINE context
memset(¶ms, 0, sizeof(params));
params.line_len
= 128;
params.non_blocking = 0;
params.fd_in
= 0;
params.fd_out
= 1;
params.histo_len = 5;
params.auto_or_sp =
CMDLINE_TAB_SPACES;
params.tab.spaces = 3;
params.histo_shortcut = '!';
cmdline_inst = cmdline_new(¶ms);
if (NULL == cmdline_inst)
{
fprintf(stderr, "Unable to allocate a CMDLINE instance
(errno = %d)\n", errno);
rc = 1;
goto error;
}
// Set debug level
cmdline_set_debug_level(cmdline_inst,
dbg);
// Set function key callback
cmdline_function_key(cmdline_inst,
function_key);
do
{
// Display the prompt
printf("%s ", cmdline_prompt);
fflush(stdout);
p = cmdline_interact(cmdline_inst);
if (p)
{
printf("The command line is:
<%s>\n", p);
}
else
{
if (ECONNRESET == errno)
{
printf("End of
session\n");
rc = 0;
break;
}
rc = 1;
break;
}
} while (p);
// Deallocate the command line instance
cmdline_delete(cmdline_inst);
rc = 0;
error:
return rc;
} // main
The previous example can be compiled as follow:
> gcc test.c
-lcmdline
> ./a.out
$$ qwerty
The command line is:
<qwerty>
$$ foo bar
The command line is:
<foo bar>
$$
Function key 4 has
been pressed (cursor pos = 0)
$$ New cmd_line
The command line is:
<New cmd_line>
$$ <CTRL
D> End of session
>
About the
author
The author is an engineer in computer sciences located in France. He is
glad to graciously offer this utility under the GPL open
source
license. He can be contacted at "rachid dot koucha at free dot fr" or
you can have a look at his WEB
home page.
Related links