DragonFly On-Line Manual Pages
MKCMD(5L) MKCMD(5L)
NAME
mkcmd - command line option packages for common facilities
SYNOPSIS
std_control.m std_help.m std_macro.m std_noargs.m std_targets.m
std_version.m cmd.m cmd_cd.m cmd_echo.m cmd_exec.m cmd_help.m
cmd_macro.m cmd_merge.m cmd_parse.m cmd_shell.m cmd_source.m
cmd_umask.m cmd_version.m
DESCRIPTION
Mkcmd builds a C application's command line option parser from
descriptions of the acceptable options. To provide some common user
support features (like on-line help) in a consistent manner, mkcmd
supplies some prefabricated option packages. This manual page
describes the option packages supplied with mkcmd 7.x. It also
provides some additional clues for constructing your own packages.
A package provides some options and control points which provide an
independent service to the user. Packages may provide C functions
(enclosed in %c...%%), header information (enclosed in %h...%%),
includes and externs (enclosed in %i...%%), or just tune parameters in
mkcmd to produce custom parsers.
C functions made available to the implementor may be called as
described below -- any other use of these functions may break in
subsequent releases.
Services provided may not be directly related to the function of the
application. For example, std_help.m (standard help dot-m) provides
the command line option `-h' (the online help facility) and some error
traps. These are not really part of the function of an application,
but they are handy to provide.
Other services provided are meant to take the place of common command
line processing. I invite any implementor to submit new standard
option descriptions to be included in the next release of mkcmd.
OPTION TEMPLATES
The distributed packages contain the following options:
std_help.m -h print this help message
Provides handling of missing parameters, and unknown options.
No implementor support is required. Every user-level shell
utility should include std_help.m in the construction of its
command line option parser, unless -h is used for something else
(and cannot be renamed).
std_macro.m -o macro[=value] turn macro on, or assign it a value
+o [macro] reset macro, or list all macros
Support a simple list of macro names and text values. The -o
option sets macro to the value provided. If no value is given
the third column in the aMC table (below) is consulted. The +o
escape binds macro to the fourth column in the aMC table.
void DoMacro(char *)
The guts of the -o facility. Not a good entry point to call
yourself.
void UndoMacro(char *)
The guts of the +o facility.
void ListMacros(FILE *)
This C function outputs each macro with its current value -- +o
with no macro after it activates the facility.
#define ENDMACRO
This C preprocessor macro must be the last line in the
definition of aMC.
char *Macro(char *)
This function returns the value bound to a macro or the unique
character array u_acFail if the macro is not in the aMC table.
The implementor must provide (visible from main):
%c
MACRO aMC[] = {
/* name no -o,+o -o +o */
{"macro", "init-value", "set-value", "reset-value"},
...
ENDMACRO/* must always be last in table */
};
%%
In practice these options are used to implement less often used
switches in the guts of a very complex application. For example
ksh's ``set -o vi'' feature. The macro's value is read by the
application with `pcValue = Macro("name");'.
std_noargs.m list
When additional words are left on the command line this facility
issues a usage message and aborts. Consumes the list control
point.
std_version.m -V show version information
Provides `-V' to output the version of the application. The
implementor must provide a rcsid visible from main. For
example:
%c
static char rcsid[] =
"$Id: ...$";
%%
The applications writer may augment the -V action's user
attribute to display more text on stdout.
std_control.m -n do not execute commands, trace only
-v be verbose
The implementor uses these to control the application of system
calls which alter the system. The names of the control
variables are fExec and fVerbose. If fExec is non-zero then the
application should take the action. If fVerbose is non-zero
that the application should output (on stdout) shell commands
which closely approximate the actions the application is taking.
Note that -n on the command line always forces -v.
For example:
if (fVerbose) {
printf("%s: rm -f %s\n", progname, pcFile);
}
if (fExec && -1 == unlink(pcFile)) {
fprintf(stderr, "%s: unlink: %s: %s\n", progname, pcFile, ...
exit(1);
}
std_targets.m none
Provide no options. No implementor support required. This
template inserts header comment with marked lines for the mk(1L)
program.
INTERACTIVE TEMPLATES
Mkcmd has some support for interactive products like lpc which have
micro-shell interpreters to control advanced features. The interpreter
uses the same rules used to split options from an environment variables
to break a command into an argument vector. The interpreter searches a
table of commands for the first word of the subsequently formed
command. A function pointer and a mask of special bits complete the
execution of the command.
The application must provide 2 definitions and a call to cmd_init to
use the interpreter. The first definition is a list of the commands to
be included in the interpreter. Each command is described as a C
structure:
typedef struct CPnode {
char *pccmd; /* command name, "quit" */
char *pcdescr; /* command help text, "terminate this" */
int (*pfi)(); /* function to call */
int facts; /* action to take after function call */
char *pcparams; /* an optional usage message for params */
} CMD;
The list of commands is an array of these structures. For example:
CMD CMList[] = {
{"page", "display a file", page_stuff, 0, "[files]"},
{"move", "move files", relocate, 0, "files to"},
CMD_DEF_QUIT,
....
};
Some of these lines are provided as C preprocessor macros in the
templates below. They are all named like CMD_DEF_name.
The other definition you must have is a variable of type `CMDSET'.
Any name will do. It must be in an appropriate scope, of course.
Something like:
CMDSET CSUser;
We are going to pass the address of this structure (as the first
parameter) to all the routines that implement the interpreter. To
complete the activation of the generic interpreter we have to call
cmd_init before we try to process any commands (see below).
These parameters tune the behavior of the interpreter as a whole. Each
command in the interpreter has a set of bits that control just that
command. In the CMD definition these facts bits may be set (and or'd
together):
CMD_NULL take no special action
CMD_RET return from the parser after this command
CMD_OFF this command is off (maybe privileged)
CMD_HIDDEN this command not in the `commands' or `help' list
CMD_NO_FREE do not free argument vector
(because command records a pointer into it)
Commands are interfaced to the interpreter as C functions that take a
standard argc, argv pair and a pointer to a command interpreter data
structure.
int
myfunction(argc, argv, pCS)
int argc;
char **argv;
CMDSET *pCS;
{
...
}
The following text describes the facilities provided by each
cmd_thing.m source file in the mkcmd standard library. Each templates
below implements either part of the interpreter infrastructure or some
standard functions.
cmd.m quit exit this command interpreter
The C preprocessor macro CMD_DEF_QUIT provides an initializer
for a CMD that implements a ``quit'' command.
This is the main code for the interpreter. Include this file in
the mkcmd command line before the file which contains the list
of commands and the command set declaration.
cmd_init(CMDSET *, CMD *, unsigned int, char *, int);
The parameters to cmd_init are (in order):
the address of a CMDSET structure
the address of the first element of the list of commands
the number of commands in that list
a string prompt, or the NULL pointer (viz. (char *))
the minimum number of character to accept for a shortened
command name, or zero
For example we might setup the new interperter ``CSUser'' with
the list of commands in the array aCMList and a generic prompt,
and a minimum command length of 3 characters as:
cmd_init(& CSUser, aCMList, sizeof(CMList)/sizeof(CMD),
"prompt> ", 3);
Once this init routine has been called two other facilities are
available to process commands. They are usually bound the -c
and -f (see below).
int cmd_from_file(CMDSET *, FILE *)
This function reads and interprets commands from the given (FILE
*). It might be used at the zero control to process commands
from stdin, e.g.:
zero {
update ``cmd_from_file(& CSUser, stdin)''
}
int cmd_from_string(CMDSET *, char *, int *)
This function interprets a single command from a string. If the
third argument to cmd_from_string is the address of an int
buffer a copy of the facts member from the active CMD entry for
the executed command is stored here. These bits are used
internally, most implementors will have little use for them:
just pass `(int *)0' as the third argument to cmd_from_string.
int (*cmd_unknown)();
int (*cmd_ambiguous)();
int (*cmd_not_available)();
These function pointers are hooks to catch bad commands. For
example cmd_unknown is used by the cmd_macro facility to trap
unknown commands which might be macro names. If your facility
cannot process or recover it should chain to the older function
(so record the old value before you stomp on it). All of these
functions take the standard 3 parameters (argc, argc, pCS).
int _cmd_unknown(int, char **, CMDSET *);
int _cmd_ambiguous(int, char **, CMDSET *);
int _cmd_not_available(int, char **, CMDSET *);
These are the default functions for the hooks above.
cmd_cd.m cd change directory
chdir change directory
This command emulates sh's builtin cd command to change the
process's current working directory. The C preprocessor macro
CMD_DEF_CD provides an initializer for the ``cd'' command. The
C preprocessor macro CMD_DEF_CHDIR provides an initializer for a
``chdir'' alias.
int cmd_cd(int, char **, CMDSET *)
This routine knows about the tilde (``~'') expansion, but not
file globbing. With no arguments, change to $HOME.
cmd_echo.m echo print text to stdout
This is included mostly as an example of a simple command. The
C preprocessor macro CMD_DEF_ECHO provides an initializer for
the ``echo'' command.
int cmd_echo(int, char **, CMDSET *)
Any arguments are output on a single line to stdout.
cmd_exec.m pwd runs /bin/pwd
This package uses the name of the command in an extended mode to
run a command from the file sysem. After the name of the
command put a literal NUL (\000) character then the path to the
binary file. The macro CMD_DEF_PWD provides an initializer for
the ``pwd'' command.
int cmd_fs_exec(int, char **, CMDSET *)
This C function looks beyond the end of the argv[0] string for a
path to execute. Put the path in the CMD initializer as:
{ ``pwd\0/bin/pwd'', ``print working directory'', cmd_fs_exec,
0}
cmd_help.m commands output a terse list of commands
help output a help message
The C preprocessor macro CMD_DEF_COMMANDS provides an
initializer for a CMD that implements a command that displays
the names of all of the available commands. Some support code
is also included.
The C preprocessor macro CMD_DEF_HELP provides an initializer
for a CMD that implements a command that displays the
descriptions for all the available commands.
cmd_macro.m macro=value set a macro
-macro activate macro
+macro deactivate macro
?macro output macro value
? output all macro values
This provides a command interface to the std_macro macros. Each
macro in the aMC array becomes 4 commands (set, activate,
deactivate, and print).
The routine cmd_macro_install() was called to install this
facility in older mkcmd libraries: that is no longer the case.
Remove any references to this function.
cmd_merge.m
This interface provides no commands unto itself. It provides a
C routine (viz. cmd_merge) which adds new commands to an
existing interpreter. This is used in conjunction with
cmd_parse.m and cmd_source.m to add commands form a table at
run-time.
int cmd_merge(CMDSET *, CMD *, unsigned int, int (*)())
Cmd_merge takes four parameters: the address of a CMDSET
structure, a pointer to the list of CMD structures, a count of
the number of CMDs provided and a function pointer to compare
two CMD structures for order. A NULL function pointer (viz.
(int (*)())0) may be supplied as the last parameter to activate
an internal function which sorts as strcmp does.
cmd_parse.m
This interface provides no commands unto itself. It provides a
C routine (viz. cmd_parse) which reads command descriptions from
a (FILE *). Commands are stored in a text table with lines that
look like:
path argv0 params -- helptext
The params are optional as is argv0. If no argv0 is provided
the tail of path is assumed.
Two optional flags may prefix the path: exclamation point (!)
declares that the new command is CMD_OFF by default, and
commercial at (@) declares that the command is hidden.
int cmd_parse(FILE *, CMD **, unsigned int *)
The usage of this routine is more clear in an example (see
below), basically we fopen(3) a file, pass this file handle and
the address of two buffers (a CMD *, and an unsigned int), close
the file. Now the (CMD *) should point to a malloc(3) area
which holds all the data about the requested commands.
Each command is setup for execution via cmd_fs_exec which must
be included as cmd_exec.m on the mkcmd command line.
cmd_shell.m shell spawn a subshell
The C preprocessor macro CMD_DEF_SHELL provides an initializer
for a CMD that spawns a copy of the user's shell, or /bin/sh if
$SHELL is not set.
int cmd_shell(int, char **, CMDSET *)
If no arguments are provided a ``-i'' is forced into the shell's
command line.
cmd_source.m source interpret files of commands
The C preprocessor macro CMD_DEF_SOURCE provides an initializer
for a CMD that read commands from a list of files.
int cmd_source(int, char **, CMDSET *)
Each file provided on the command line is opened in turn and
read as commands to the interpreter.
cmd_umask.m umask print/set file creation mask
The C preprocessor macro CMD_DEF_UMASK provides an initializer
for a CMD that prints (sets) the process's file creation mask.
int cmd_umask(int, char **, CMDSET *)
This C routine implements the umask command. In addition the
POSIX -S option is emulated if NEED_SYMBOLIC_UMASK is defined to
be non-zero (which is the default).
cmd_version.m version output a version string
The C preprocessor macro CMD_DEF_VERSION provides an initializer
for a CMD that outputs the rcsid as a version string.
int cmd_version(int, char **, CMDSET *)
This C routine outputs rcsid the version of the program. The
implementor must provide this character array.
EXAMPLES
Mkcmd has a simple syntax and a declarative nature -- none of the
examples below are mind bogglingly ``clever''.
To allow exactly two positional parameters (a file and an integer):
integer variable "iSize" {
parameter "size"
help "maximum size to grow file"
}
fd ["O_CREAT|O_RDWR, 644"] variable "fdOutFile" "pcOutFile" {
parameter "file"
help "file to append message"
}
left "fdOutFile" "iSize" {
}
To make -v and -s be opposites (verbose and silent):
boolean 'v' {
named "fVerbose"
init "0"
help "be verbose"
}
action 's' {
update "%rvn = 0;"
help "be silent (turn off verbose)"
}
To augment the standard version option to output additional stuff (note
that the percent and the backslash must be quoted):
augment action 'V' {
user 'printf("%%s: additional stuff\\n", %b);'
}
To allow access to a cmd interpreter from the command line:
function 'c' {
track named "cmd_from_string"
update '%n(& CSGlobal, %N, (int *)0);'
parameter "cmd"
help "provide an interactive command"
}
If the user should be able to source a file with -f:
file 'f' {
track named "fpSource" "pcSource"
user 'cmd_from_file(& CSGlobal, %n);'
help "interpret commands from file"
}
If no -c or -f options are given we might use zero to drop into an
interactive mode:
zero {
named "cmd_from_file"
update 'if (!%rcU && !%rfU) {%n(& CSGlobal, stdin);}'
}
To read file system commands from a map file (see cmd_parse.m,
cmd_exec.m and cmd_merge.m):
auto unsigned int ui;
auto CMD *pCMMerge;
...
if ((FILE *)0 != (fpCmds = fopen(acAddCmds, "r"))) {
if (0 == cmd_parse(fpCmds, & pCMMerge, & uiMerge) && 0 != uiMerge) {
cmd_merge(pCS, pCMMerge, uiMerge, (int (*)())0);
}
(void)fclose(fpCmds);
}
BUGS
Some more attention should be given to the C code supplied.
The internal percent-based code generator is too cryptic for most
programmers to use effectively.
FILES
/usr/local/share/mkcmd the default directory for template files
AUTHOR
Kevin S Braunsdorf
Federal Express
ksbrauns@fedex.com
SEE ALSO
sh(1), execve(2), mk(1L), umask(2), ch(2)
LOCAL MKCMD(5L)