This document describes a library of data structures and functions developed over the years for programs in the Occasional Publications in Academic Computing series published by SIL International. (For SIL International, "academic" refers to linguistics, literacy, anthropology, translation, and related fields.) It is hoped that this documentation will make future maintenance of these programs easier.
This particular function library is used by the PC-Kimmo and PC-PATR programs. It is quite possible that no other programs will be developed using this style of user interface, since the whole world has been convinced that hand-eye coordination is the most important talent for using a computer, that is, pointing and clicking with a mouse is universally considered better than typing commands.
The basic goal behind choosing names in the CMD function library is for the name to convey information about what it represents. This is achieved in two ways: striving for a descriptive name rather than a short cryptic abbreviated name, and following a different pattern of capitalization for each type of name.
Preprocessor macro names are written entirely in capital letters. If
the name requires more than one word for an adequate description, the
words are joined together with intervening underscore (_
)
characters.
Data structure names consist of one or more capitalized words. If the name requires more than one word for an adequate description, the words are joined together without underscores, depending on the capitalization pattern to make them readable as separate words.
Variable names in the CMD function library follow a modified form of the Hungarian naming convention described by Steve McConnell in his book Code Complete on pages 202-206.
Variable names have three parts: a lowercase type prefix, a descriptive name, and a scope suffix.
The type prefix has the following basic possibilities:
b
char
, short
, or int
c
char
but sometimes a short
or
int
d
double
e
enum
or as a char
,
short
, or int
i
int
, short
, long
, or
(rarely) char
s
struct
statement
sz
pf
In addition, the basic types may be prefixed by these qualifiers:
u
a
p
The descriptive name portion of a variable name consists of one or more
capitalized words concatenated together. There are no underscores
(_
) separating these words from each other, or from the type
prefix. For the CMD function library, the descriptive
name for global variables
begins with a reference to the relevant CMD data structure.
The scope suffix has these possibilities:
_g
_m
static
)
_in
_out
_io
_s
static
)
The lack of a scope suffix indicates that a variable is declared within a function and exists on the stack for the duration of the current call.
Global function names in the CMD function library have
two parts: a verb that is all lowercase followed by a noun phrase
containing one or more capitalized words. These pieces are
concatanated without any intervening underscores (_
). For the
CMD library functions, the noun phrase section
includes
a reference to the relevant CMD data structure.
Given the discussion above, it is easy to discern at a glance what type of item each of the following names refers to.
SAMPLE_NAME
SampleName
pSampleName
writeSampleName
SampleName
).
This chapter describes the data structure defined for the CMD function
library. The CMD function library also makes heavy use of the
NumberedMessage
data structure from the OPAC function library.
See section `NumberedMessage' in OPAC Function Library Reference Manual.
#include "cmd.h" typedef struct { char * pszKeyword; int iValue; int iFlags; } CmdKeyword;
CmdKeyword
is a data structure for building command keyword
tables (arrays) for programs that use an interactive user interface
based on typing commands.
The fields of the CmdKeyword
data structure are as follows:
pszKeyword
NUL
-terminated keyword string.
iValue
iFlags
iFlags & CMD_INVISIBLE
iFlags & CMD_DISABLED
`cmd.h'
This chapter gives the proper usage information about each of the global variables found in the CMD function library. For each global variable that the library provides, this information includes which CMD library functions use it.
#include "cmd.h" extern int bCmdShowWarnings_g;
The CMD function library uses displayNumberedMessage
(see section `displayNumberedMessage' in OPAC Function Library Reference Manual)
to display error and warning messages. bCmdShowWarnings_g
determines what to do with messages of type WARNING_MSG
. If
bCmdShowWarnings_g
is FALSE
(zero), then messages are
totally ignored unless they are of type ERROR_MSG
. This
includes both screen display and writing the message to a log file.
The default value of bCmdShowWarnings_g
is TRUE
(1
).
4.1.3 Example See section 6. Sample Program.
4.1.4 Source File `cmdmessg.c'
4.1.5 Used By
doCmdChdir
doCmdClose
doCmdEdit
doCmdLog
doCmdTake
#include "cmd.h" extern int bCmdSilentMessages_g;
The CMD function library uses displayNumberedMessage
(see section `displayNumberedMessage' in OPAC Function Library Reference Manual)
to display error and warning messages. If bCmdSilentMessages_g
is TRUE
(nonzero), then messages are not displayed on the
screen; they may, however, still be written to a log file. If
bCmdSilentMessages_g
is FALSE
(zero), then messages are
displayed on the screen, and may also be written to a log file.
The default value of bCmdSilentMessages_g
is FALSE
(0
).
4.2.3 Example See section 6. Sample Program.
4.2.4 Source File `cmdmessg.c'
4.2.5 Used By
doCmdChdir
doCmdClose
doCmdEdit
doCmdLog
doCmdTake
#include "cmd.h" extern FILE * pCmdLogFP_g;
The CMD function library uses displayNumberedMessage
(see section `displayNumberedMessage' in OPAC Function Library Reference Manual)
to display error and warning messages. pCmdLogFP_g
points to an
optional output log file used to record the messages displayed by
displayNumberedMessage
. The application program can use it to
record other information as well.
The default value of pCmdLogFP_g
is NULL
(no log file).
4.3.3 Example See section 6. Sample Program, section 4.13 sCmdClosingLog_g, and section 4.24 sCmdNoLogFile_g.
4.3.4 Source File `cmddata.c'
4.3.5 Used By
doCmdTake
doCmdChdir
doCmdEdit
doCmdLog
doCmdClose
#include "cmd.h" extern FILE * pCmdOutputFP_g;
pCmdOutputFP_g
is used by handleCmdSigint
, as a means to
safely close an output file when processing is interrupted by the user.
It may also be used by the application program to refer to the output
file.
The default value of pCmdOutputFP_g
is NULL
(no output
file to close).
4.4.3 Example See section 6. Sample Program.
4.4.4 Source File `cmddata.c'
4.4.5 Used By
handleCmdSigint
#include "cmd.h" extern char * pszCmdLogFile_g;
pszCmdLogFile_g
records the name of the output log file opened
for pCmdLogFP_g
.
The default value for pszCmdLogFile_g
is NULL
(no log
file).
4.5.3 Example See section 6. Sample Program, section 4.13 sCmdClosingLog_g, and section 4.24 sCmdNoLogFile_g.
4.5.4 Source File `cmddata.c'
4.5.5 Used By
doCmdClose
doCmdLog
#include "cmd.h" extern char * pszCmdProgramName_g;
pszCmdProgramName_g
points to a form of the application
program's name that is suitable for serving as the basis of a
filename.
The default value of pszCmdProgramName_g
is NULL
(no
program name).
4.6.3 Example See section 6. Sample Program, and section 4.13 sCmdClosingLog_g.
4.6.4 Source File `cmddata.c'
4.6.5 Used By
doCmdLog
doCmdSystem
doCmdTake
#include "cmd.h" extern NumberedMessage sCmdAmbiguousKeyword_g;
sCmdAmbiguousKeyword_g
is defined as follows:
NumberedMessage sCmdAmbiguousKeyword_g = { ERROR_MSG, 105, "Ambiguous keyword in %s command: %s" };
See section 6. Sample Program.
4.7.4 Source File `messages.c'
4.7.5 Used By
#include "cmd.h" extern NumberedMessage sCmdAmbiguous_g;
sCmdAmbiguous_g
is defined as follows:
NumberedMessage sCmdAmbiguous_g = { ERROR_MSG, 101, "Ambiguous command: %s" };
See section 6. Sample Program.
4.8.4 Source File `messages.c'
4.8.5 Used By
#include "cmd.h" extern NumberedMessage sCmdBadArgument_g;
sCmdBadArgument_g
is defined as follows:
NumberedMessage sCmdBadArgument_g = { ERROR_MSG, 107, "Invalid argument in %s command: %s" };
See section 6. Sample Program.
4.9.4 Source File `messages.c'
4.9.5 Used By
#include "cmd.h" extern NumberedMessage sCmdBadInputFile_g;
sCmdBadInputFile_g
is defined as follows:
NumberedMessage sCmdBadInputFile_g = { ERROR_MSG, 109, "Cannot open input file %s in %s command" };
See section 6. Sample Program.
4.10.4 Source File `messages.c'
4.10.5 Used By
doCmdTake
#include "cmd.h" extern NumberedMessage sCmdBadKeyword_g;
sCmdBadKeyword_g
is defined as follows:
NumberedMessage sCmdBadKeyword_g = { ERROR_MSG, 106, "Invalid keyword in %s command: %s" };
See section 6. Sample Program.
4.11.4 Source File `messages.c'
4.11.5 Used By
#include "cmd.h" extern NumberedMessage sCmdBadOutputFile_g;
sCmdBadOutputFile_g
is defined as follows:
NumberedMessage sCmdBadOutputFile_g = { ERROR_MSG, 110, "Cannot open output file %s in %s command" };
See section 6. Sample Program, and section 4.13 sCmdClosingLog_g.
4.12.4 Source File `messages.c'
4.12.5 Used By
doCmdLog
#include "cmd.h" extern NumberedMessage sCmdClosingLog_g;
sCmdClosingLog_g
is defined as follows:
NumberedMessage sCmdClosingLog_g = { WARNING_MSG, 114, "Closing the existing log file %s" };
This example is the actual library function source code (at least when this documentation was written).
4.13.3 Example
#include <stdio.h> #include "allocmem.h" #include "cmd.h" ... void doCmdLog(pszFilename_in) const char * pszFilename_in; { char buffer[80]; char * pszFilename; sprintf(buffer, "LOG [<file>] (default is %s.log)", pszCmdProgramName_g ? pszCmdProgramName_g : "log"); if (wantCmdHelp(pszFilename_in, buffer)) return; if (pCmdLogFP_g != NULL) fclose(pCmdLogFP_g); if (pszCmdLogFile_g != NULL) { displayNumberedMessage(&sCmdClosingLog_g, NULL, NULL, pszCmdLogFile_g); freeMemory(pszCmdLogFile_g); pszCmdLogFile_g = NULL; } sprintf(buffer, "%s.log", pszCmdProgramName_g ? pszCmdProgramName_g : "log"); pszFilename = setCmdFilename(pszFilename_in, buffer, ".log"); pCmdLogFP_g = fopen(pszFilename,"w"); if (pCmdLogFP_g == NULL) { displayNumberedMessage(&sCmdBadOutputFile_g, NULL, NULL, pszFilename, "LOG"); freeMemory(pszFilename); } else pszCmdLogFile_g = pszFilename; }
`messages.c'
4.13.5 Used By
doCmdLog
#include "cmd.h" extern NumberedMessage sCmdErrorInTake_g;
sCmdErrorInTake_g
is defined as follows:
NumberedMessage sCmdErrorInTake_g = { ERROR_MSG, 112, "TAKE file aborted due to invalid command: %s" };
See section 6. Sample Program.
4.14.4 Source File `messages.c'
4.14.5 Used By
#include "cmd.h" extern NumberedMessage sCmdInvalidDirectory_g;
sCmdInvalidDirectory_g
is defined as follows:
NumberedMessage sCmdInvalidDirectory_g = { ERROR_MSG, 117, "Bad pathname for CD command" };
This example is simpler than the actual library function source code.
#include <stdlib.h> #include "cmd.h" ... void doCmdChdir(pszPathname_in) const char * pszPathname_in; { char szPathname[1026]; char * pszHomeDir; const char * pszDirectory; if ((pszPathname_in == NULL) || (*pszPathname_in == NUL)) { /* default to home directory */ pszHomeDir = getenv("HOME"); if (pszHomeDir != NULL) pszDirectory = pszHomeDir; else { displayNumberedMessage(&sCmdMissingDirectory_g, NULL, NULL); return; } } else pszDirectory = pszPathname_in; if (wantCmdHelp(pszPathname_in, "CD <pathname> (no default)\n")) return; if (getcwd(szPathname, 1026) == NULL) { perror("CD"); return; } if (chdir(pszDirectory) != 0) { chdir(szPathname); displayNumberedMessage(&sCmdInvalidDirectory_g, NULL, pszPathname_in); return; } if (getcwd(szPathname, 1026) != NULL) fprintf(stderr, "%s\n", szPathname); else perror("CD"); }
`messages.c'
4.15.5 Used By
doCmdChdir
#include "cmd.h" extern NumberedMessage sCmdInvalid_g;
sCmdInvalid_g
is defined as follows:
NumberedMessage sCmdInvalid_g = { ERROR_MSG, 102, "Invalid command: %s" };
See section 6. Sample Program.
4.16.4 Source File `messages.c'
4.16.5 Used By
#include <setjmp.h> #include "cmd.h" extern jmp_buf sCmdJmpBuf_g;
sCmdJmpBuf_g
is used by handleCmdSigint
to jump out of an
undesired situation back to the beginning of the command loop. It must
be filled by setjmp
before calling signal
with
handleCmdSigint
.
4.17.3 Example See section 6. Sample Program.
4.17.4 Source File `cmdsig.c'
4.17.5 Used By
handleCmdSigint
#include "cmd.h" extern NumberedMessage sCmdMissingArgument_g;
sCmdMissingArgument_g
is defined as follows:
NumberedMessage sCmdMissingArgument_g = { ERROR_MSG, 104, "Missing argument in %s command" };
See section 6. Sample Program.
4.18.4 Source File `messages.c'
4.18.5 Used By
#include "cmd.h" extern NumberedMessage sCmdMissingDirectory_g;
sCmdMissingDirectory_g
is defined as follows:
NumberedMessage sCmdMissingDirectory_g = { ERROR_MSG, 116, "Missing pathname for CD command" };
See section 4.15 sCmdInvalidDirectory_g.
4.19.4 Source File `messages.c'
4.19.5 Used By
doCmdChdir
#include "cmd.h" extern NumberedMessage sCmdMissingEditFile_g;
sCmdMissingEditFile_g
is defined as follows:
NumberedMessage sCmdMissingEditFile_g = { ERROR_MSG, 115, "Missing filename for EDIT command" };
This example is simpler than the actual library function source code.
#include <stdlib.h> #include "cmd.h" ... void doCmdEdit(pszFilename_in) const char * pszFilename_in; { char szEditCommand[200]; char * pszEditor; if (pszFilename_in == (char *)NULL) { displayNumberedMessage(&sCmdMissingEditFile_g, NULL, NULL); return; } if (wantCmdHelp(pszFilename_in, "EDIT <file> (no default filename or type)")) return; pszEditor = getenv("EDITOR"); if (pszEditor == NULL) pszEditor = "emacs"; sprintf(szEditCommand, "%s %s", pszEditor, pszFilename_in); doCmdSystem(szEditCommand); }
`messages.c'
4.20.5 Used By
doCmdEdit
#include "cmd.h" extern NumberedMessage sCmdMissingInputFile_g;
sCmdMissingInputFile_g
is defined as follows:
NumberedMessage sCmdMissingInputFile_g = { ERROR_MSG, 108, "Missing input file argument in %s command" };
See section 6. Sample Program.
4.21.4 Source File `messages.c'
4.21.5 Used By
#include "cmd.h" extern NumberedMessage sCmdMissingKeyword_g;
sCmdMissingKeyword_g
is defined as follows:
NumberedMessage sCmdMissingKeyword_g = { ERROR_MSG, 103, "Missing keyword in %s command" };
See section 6. Sample Program.
4.22.4 Source File `messages.c'
4.22.5 Used By
#include "cmd.h" extern NumberedMessage sCmdMissingOutputFile_g;
sCmdMissingOutputFile_g
is defined as follows:
NumberedMessage sCmdMissingOutputFile_g = { ERROR_MSG, 118, "Missing output file argument in %s command" };
See section 6. Sample Program.
4.23.4 Source File `messages.c'
4.23.5 Used By
#include "cmd.h" extern NumberedMessage sCmdNoLogFile_g;
sCmdNoLogFile_g
is defined as follows:
NumberedMessage sCmdNoLogFile_g = { ERROR_MSG, 113, "No log file was open" };
This example is the actual library function source code (at least when this documentation was written).
void doCmdClose() { if ((pCmdLogFP_g == NULL) && (pszCmdLogFile_g == NULL)) { displayNumberedMessage(&sCmdNoLogFile_g, NULL, NULL); return; } if (pCmdLogFP_g != (FILE *)NULL) { fclose(pCmdLogFP_g); pCmdLogFP_g = (FILE *)NULL; } if (pszCmdLogFile_g != (char *)NULL) { freeMemory(pszCmdLogFile_g); pszCmdLogFile_g = (char *)NULL; } }
`messages.c'
4.24.5 Used By
doCmdClose
#include "cmd.h" extern NumberedMessage sCmdTooDeepTake_g;
sCmdTooDeepTake_g
is defined as follows:
NumberedMessage sCmdTooDeepTake_g = { ERROR_MSG, 111, "TAKE files nested too deeply" };
This example is the actual library function source code (at least when this documentation was written).
#include <stdio.h> #include "opaclib.h" #include "cmd.h" ... typedef struct { FILE * pInputFP; char * pszFilename; unsigned uiLineNumber; } CmdTakeFile; #define CMD_TAKE_LEVELS 3 static CmdTakeFile asTake_m[CMD_TAKE_LEVELS]; static int iTakeLevel_m = -1; static char szTakeUsage_m[] = "TAKE [<file>] (default name is %s.tak, default type is .tak)"; ... void doCmdTake(char * pszFilename_in) { char * pszFile; char * p; char szBuffer[128]; if (iTakeLevel_m >= CMD_TAKE_LEVELS-1) { displayNumberedMessage(&sCmdTooDeepTake_g, NULL, NULL); return; } if ((pszCmdProgramName_g != NULL) && (*pszCmdProgramName_g != NUL)) sprintf(szBuffer, szTakeUsage_m, pszCmdProgramName_g); else sprintf(szBuffer, szTakeUsage_m, "cmd"); if (wantCmdHelp(pszFilename_in, szBuffer)) return; if ((pszCmdProgramName_g != NULL) && (*pszCmdProgramName_g != NUL)) sprintf(szBuffer, "%s.tak", pszCmdProgramName_g); else strcpy(szBuffer, "cmd.tak"); pszFile = setCmdFilename(pszFilename_in, szBuffer, ".tak"); if (iTakeLevel_m > -1) { p = buildAdjustedFilename(pszFile, asTake_m[iTakeLevel_m].pszFilename, NULL); freeMemory( pszFile ); pszFile = p; } ++iTakeLevel_m; asTake_m[iTakeLevel_m].pInputFP = fopen(pszFile, "r"); if (asTake_m[iTakeLevel_m].pInputFP == NULL) { displayNumberedMessage(&sCmdBadInputFile_g, NULL, NULL, pszFile, "TAKE"); --iTakeLevel_m; freeMemory(pszFile); } else { asTake_m[iTakeLevel_m].uiLineNumber = 1; asTake_m[iTakeLevel_m].pszFilename = pszFile; } }
`messages.c'
4.25.5 Used By
doCmdTake
This chapter gives the proper usage information about each of the functions found in the CMD function library. The prototypes and type definitions relevent to the use of these functions are all found in the `cmd.h' header file.
5.1.1 Syntax
#include "cmd.h" int closeCmdTake(void);
closeCmdTake
closes the current "take" file, if any are open.
If there were two or more "take" files open, future calls to
getCmdString
will read from the parent "take" file.
Otherwise, this causes getCmdString
to read from the keyboard.
closeCmdTake
does not have any arguments.
5.1.3 Return Value
the number of (nested) "take" files open when closeCmdTake
finishes
5.1.4 Example See section 6. Sample Program.
5.1.5 Source File `cmd.c'
5.2.1 Syntax
#include "cmd.h" void doCmdChdir(const char * pszDirectory_in);
doCmdChdir
executes a "change directory" command. If read
from a "take" file, it is relative to the location of the take file
unless an absolute path is given.
doCmdChdir
has one argument:
pszDirectory_in
none
5.2.4 Example See section 6. Sample Program, and section 4.15 sCmdInvalidDirectory_g.
5.2.5 Source File `cmdcd.c'
5.3.1 Syntax
#include "cmd.h" void doCmdClose(void);
doCmdClose
closes the currently open log file, clearing the
global variables pCmdLogFP_g
and pszCmdLogFile_g
. It is
designed to perform the operation of an interactive `close'
command.
doCmdClose
does not have any arguments.
5.3.3 Return Value none
5.3.4 Example See section 6. Sample Program.
5.3.5 Source File `cmdlog.c'
5.4.1 Syntax
#include "cmd.h" void doCmdDirectory(const char * pszArgument_in);
doCmdDirectory
lists the contents of a directory on the screen.
It is designed to to perform an interactive `directory <options>'
command.
doCmdDirectory
works by running the operating system's standard
directory listing program as a subprocess. It does not work on the
Macintosh.
doCmdDirectory
has one argument:
pszArgument_in
NULL
.
none
5.4.4 Example See section 6. Sample Program.
5.4.5 Source File `cmddir.c'
5.5.1 Syntax
#include "cmd.h" void doCmdEdit(const char * pszFilename_in);
doCmdEdit
edits a file. It is designed to to perform an
interactive `edit <filename>' command.
doCmdEdit
works by running a text editor program as a
subprocess. Either the program specified by the `EDITOR'
environment variable or a standard editor is used. For MS-DOS, this is
`edit'; for Unix, this is `emacs'; for VMS, this is
`edt'. doCmdEdit
does not work on the Macintosh.
doCmdEdit
has one argument:
pszFilename_in
none
5.5.4 Example See section 6. Sample Program.
5.5.5 Source File `cmdedit.c'
5.6.1 Syntax
#include "cmd.h" void doCmdLog(const char * pszFilename_in);
doCmdLog
opens a log file, setting the global variables
pCmdLogFP_g
and pszCmdLogFile_g
after automatically closing
any previously open log file. It is designed to perform the operation
of an interactive `log <filename>' command.
doCmdLog
has one argument:
pszFilename_in
none
5.6.4 Example See section 6. Sample Program, and section 4.13 sCmdClosingLog_g.
5.6.5 Source File `cmdlog.c'
5.7.1 Syntax
#include "cmd.h" void doCmdSystem(const char * pszCommand_in);
doCmdSystem
executes a system command in a subshell. It is
designed to perform the operation of an interactive
`system <command line>' command.
doCmdSystem
works by executing the command as a subprocess using
the standard shell. For MS-DOS, the standard shell is given by either
the `SHELL' or the `COMSPEC' environment variable (or
defaults to `command.com'). For Unix, the standard shell is given
by the `SHELL' environment variable (or defaults to
`/bin/sh'). For VMS, the standard shell is `DCL'.
doCmdSystem
does not work on the Macintosh.
doCmdSystem
has one argument:
pszCommand_in
NULL
.
If it is NULL
or an empty string, a subshell is spawned.
none
5.7.4 Example See section 6. Sample Program.
5.7.5 Source File `cmdsys.c'
5.8.1 Syntax
#include "cmd.h" void doCmdTake(const char * pszFilename_in);
doCmdTake
opens a "take" file, unless 3 levels of "take"
files are already open. If successful, this causes future calls to
getCmdString
to read from the "take" file.
doCmdTake
has one argument:
pszFilename_in
none
5.8.4 Example See section 6. Sample Program.
5.8.5 Source File `cmd.c'
5.9.1 Syntax
#include "cmd.h" char * getCmdString(const char * pszCommand_in, const char * pszPrompt_in, int cComment_in);
getCmdString
gets a command from the appropriate place, in this
order of priority:
doCmdTake
"Take" files are closed, and the current "take" level decremented, if the end of the current "take" file is detected.
The arguments to getCmdString
are as follows:
pszCommand_in
NULL
(the usual case).
pszPrompt_in
cComment_in
NUL
('\0'
).
a pointer to the command string (which may be overwritten by next call
to getCmdString
)
5.9.4 Example See section 6. Sample Program.
5.9.5 Source File `cmd.c'
5.10.1 Syntax
#include "cmd.h" char * getCmdTakeFile(void);
getCmdTakeFile
gets the name of the current "take" file, if
any are open.
getCmdTakeFile
does not have any arguments.
5.10.3 Return Value
the pathname of the current "take" file, or NULL
if none are
open
5.10.4 Example See section 6. Sample Program.
5.10.5 Source File `cmd.c'
5.11.1 Syntax
#include "cmd.h" int getCmdTakeLevel(void);
getCmdTakeLevel
gets the number of open "take" files.
getCmdTakeLevel
does not have any arguments.
5.11.3 Return Value the number of (nested) "take" files open
5.11.4 Example See section 6. Sample Program.
5.11.5 Source File `cmd.c'
5.12.1 Syntax
#include "cmd.h" RETSIGTYPE handleCmdSigint(int iSignal_in);
handleCmdSigint
handles SIGINT
signals by closing the
current output file and jumping to a predefined spot. It is invoked
indirectly after being established by
signal( SIGINT, handleCmdSigint );
handleCmdSigint
uses the global variables pCmdOutputFP_g
and sCmdJmpBuf_g
, setting the former to NULL
after
closing the file.
handleCmdSigint
has one argument:
iSignal_in
SIGINT
).
none (it does not return)
5.12.4 Example See section 6. Sample Program.
5.12.5 Source File `cmdsig.c'
5.13.1 Syntax
#include "cmd.h" int lookupCmdKeyword( char * pszCommand_in, const CmdKeyword * pKeywordTable_in, int iTableSize_in, char * pszHelp_in);
lookupCmdKeyword
searches the given table of command keywords
for the given command. The keyword table must be arranged in ascending
alphabetical order, and all letters must be lowercase.
A match is successful if the target matches a keyword exactly, or if the target is a prefix of exactly one keyword. It is ambiguous if the target matches two or more keywords from the table unless it matches one exactly.
The arguments to lookupCmdKeyword
are as follows:
pszCommand_in
strlwr
).
pKeywordTable_in
CmdKeyword
data structures.
iTableSize_in
pszHelp_in
NULL
, no help at all is displayed), displayed following the list
of keywords.
the keyword's associated value (iValue
) if found, or
CMD_NULL
NULL
CMD_AMBIGUOUS
CMD_INVALID
CMD_HELP
?
is found in the input command (the keyword list is
displayed automatically)
See section 6. Sample Program.
5.13.5 Source File `cmd.c'
5.14.1 Syntax
#include "cmd.h" char * setCmdFilename(const char * pszFilename_in, const char * pszDefaultName_in, const char * pszExtension_in);
setCmdFilename
sets a filename using one provided by the user,
appending the default extension if the provided filename lacks an
extension, or using a default filename.
The arguments to setCmdFilename
are as follows:
pszFilename_in
NULL
.
pszDefaultName_in
NULL
.
pszExtension_in
.
), or is NULL
.
a dynamically allocated filename string, or NULL
if
pszFilename_in
and pszDefaultName_in
are both NULL
5.14.4 Example See section 6. Sample Program.
5.14.5 Source File `setcmdfi.c'
5.15.1 Syntax
#include "cmd.h" void showCmdTiming(void );
showCmdTiming
displays the elapsed time for an operation, using
the internal values set by startCmdTiming
and
stopCmdTiming
.
showCmdTiming
does not have any arguments.
5.15.3 Return Value none
5.15.4 Example See section 6. Sample Program.
5.15.5 Source File `cmdtime.c'
5.16.1 Syntax
#include "cmd.h" void startCmdTiming(void);
startCmdTiming
sets an internal variable to the starting time of
an operation. It is useful only in conjunction with
stopCmdTiming
and showCmdTiming
.
startCmdTiming
does not have any arguments.
5.16.3 Return Value none
5.16.4 Example See section 6. Sample Program.
5.16.5 Source File `cmdtime.c'
5.17.1 Syntax
#include "cmd.h" void stopCmdTiming(void );
stopCmdTiming
sets an internal variable to the ending time of
an operation. It is useful only in conjunction with
startCmdTiming
and showCmdTiming
.
stopCmdTiming
does not have any arguments.
5.17.3 Return Value none
5.17.4 Example See section 6. Sample Program.
5.17.5 Source File `cmdtime.c'
5.18.1 Syntax
#include "cmd.h" int wantCmdHelp(const char * pszArgument_in, const char * pszHelpMessage_in);
wantCmdHelp
displays the help message if the first argument is
equal to a single question mark ("?"
).
The arguments to wantCmdHelp
are as follows:
pszArgument_in
"?"
, or is NULL
.
pszHelpMessage_in
TRUE
(nonzero) if help provided, otherwise FALSE
(zero)
5.18.4 Example See section 6. Sample Program.
5.18.5 Source File `wanthelp.c'
Rather than try to create small code fragments to illustrate each of the functions and global variables in the CMD function library, a complete (but rather useless) sample program is provided in this chapter. It has been compiled correctly on Unix systems (actually Linux and SunOS).
/* SAMPLE.C - sample program for the CMD function library ******************************************************************* * Copyright 1997 by SIL International. */ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #include <time.h> #include "cmd.h" #include "opaclib.h" #define KW_CHDIR 1 #define KW_CLOSE 2 #define KW_DIRECTORY 3 #define KW_EDIT 4 #define KW_HELP 5 #define KW_LOAD 6 #define KW_LOG 7 #define KW_PROCESS 8 #define KW_QUIT 9 #define KW_SAVE 10 #define KW_SET 11 #define KW_SHOW 12 #define KW_SYSTEM 13 #define KW_TAKE 14 static CmdKeyword asCommandTable_m[] = { { "cd", KW_CHDIR, CMD_INVISIBLE }, { "chdir", KW_CHDIR, 0 }, { "close", KW_CLOSE, 0 }, { "directory", KW_DIRECTORY, 0 }, { "edit", KW_EDIT, 0 }, { "exit", KW_QUIT, CMD_INVISIBLE }, { "help", KW_HELP, 0 }, { "load", KW_LOAD, 0 }, { "log", KW_LOG, 0 }, { "ls", KW_DIRECTORY, CMD_INVISIBLE }, { "process", KW_PROCESS, 0 }, { "quit", KW_QUIT, 0 }, { "save", KW_SAVE, 0 }, { "set", KW_SET, 0 }, { "show", KW_SHOW, 0 }, { "system", KW_SYSTEM, 0 }, { "take", KW_TAKE, 0 } }; static int iCommandTableSize_m = (sizeof(asCommandTable_m) / sizeof(CmdKeyword)); static char szProcessUsage_m[] = "PROCESS <infile> <outfile> (no default filenames or types)"; #define KW_CODE 11 #define KW_COMMENT 12 #define KW_SILENT 13 #define KW_TIMING 14 #define KW_WARNING 15 static CmdKeyword asSetTable_m[] = { { "code", KW_CODE, 0 }, { "comment", KW_COMMENT, 0 }, { "silent", KW_SILENT, 0 }, { "timing", KW_TIMING, 0 }, { "warnings", KW_WARNING, 0 } }; static int iSetTableSize_m = (sizeof(asSetTable_m) / sizeof(CmdKeyword)); #define KW_OFF 16 #define KW_ON 17 static CmdKeyword asOnOffTable_m[] = { { "false", KW_OFF, CMD_INVISIBLE }, { "off", KW_OFF, 0 }, { "on", KW_ON, 0 }, { "true", KW_ON, CMD_INVISIBLE } }; static int iOnOffTableSize_m = (sizeof(asOnOffTable_m) / sizeof(CmdKeyword)); static int bTiming_m = FALSE; static int cCommentMarker_m = ';'; static unsigned char uiCode_m = 0xFF; static char szWhitespace_m[7] = " \t\r\n\f\v"; static char szPrompt_m[] = "Command>"; /******************************************************************* * NAME * do_help_set * DESCRIPTION * execute a HELP SET command * RETURN VALUE * none */ static void do_help_set(char * pszKeyword_in) { static char szGenericSet_s[] = "Type HELP SET <parameter> for more help\n"; switch (lookupCmdKeyword(pszKeyword_in, asSetTable_m, iSetTableSize_m, "")) { case CMD_NULL: fputs("\n\ set code sets the byte code value for the PROCESS command\n\ set comment sets the comment characters for TAKE files\n\ set silent enables or disables error/warning messages\n\ set timing enables or disables timing the PROCESS command\n\ set warnings enables or disables warning messages\n\ \n", stderr); fputs(szGenericSet_s, stderr); break; case CMD_AMBIGUOUS: displayNumberedMessage(&sCmdAmbiguousKeyword_g, NULL, NULL, "HELP SET", pszKeyword_in); break; case CMD_INVALID: displayNumberedMessage(&sCmdBadKeyword_g, NULL, NULL, "HELP SET", pszKeyword_in); break; case CMD_HELP: fputs(szGenericSet_s, stderr); break; case KW_CODE: fputs("\ SET CODE <number> sets the code byte for the PROCESS command to\n\ the indicated value. The default code byte is 0xFF (255).\n", stderr); break; case KW_COMMENT: fputs("\ SET COMMENT <char> sets the comment character to the indicated\n\ value. If <char> is missing (or equal to the current comment\n\ character), then comment handling is disabled. The default\n\ comment character is ';' (the semicolon).\n", stderr); break; case KW_SILENT: fputs("\ SET SILENT ON disables all error and warning messages.\n\ SET SILENT OFF enables all error and warning messages.\n\ The default is OFF.\n", stderr); break; case KW_TIMING: fputs("\ SET TIMING ON turns on timing mode, and SET TIMING OFF turns it\n\ off. If timing mode is ON, then the elapsed time required to\n\ process a command is displayed when the command finishes. If\n\ timing mode is OFF, then the elapsed time is not shown. The\n\ default is OFF.\n", stderr); break; case KW_WARNING: fputs("\ SET WARNING ON turns on warning mode. SET WARNING OFF turns off\n\ warning mode. If warning mode is ON, then warning messages are\n\ displayed on the output. If warning mode is OFF, then no warning\n\ messages are displayed. The default is ON.\n", stderr); break; } } /******************************************************************* * NAME * do_help_show * DESCRIPTION * execute a HELP SHOW command * RETURN VALUE * none */ static void do_help_show(char * pszKeyword_in) { static char szGenericShow_s[] = "Type HELP SHOW <parameter> for more help\n"; switch (lookupCmdKeyword(pszKeyword_in, asSetTable_m, iSetTableSize_m, "")) { case CMD_NULL: fputs("\n\ show code shows the byte code value for the PROCESS command\n\ show comment shows the comment characters for TAKE files\n\ show silent shows whether error/warning messages are disabled\n\ show timing shows whether timing of PROCESS command is enabled\n\ show warnings shows whether warning messages are enabled\n\ \n\ show shows all of the above values\n\ \n", stderr); fputs(szGenericShow_s, stderr); break; case CMD_AMBIGUOUS: displayNumberedMessage(&sCmdAmbiguousKeyword_g, NULL, NULL, "HELP SHOW", pszKeyword_in); break; case CMD_INVALID: displayNumberedMessage(&sCmdBadKeyword_g, NULL, NULL, "HELP SHOW", pszKeyword_in); break; case CMD_HELP: fputs(szGenericShow_s, stderr); break; case KW_CODE: fputs("\ SHOW CODE displays the code byte for the PROCESS command.\n\ ", stderr); break; case KW_COMMENT: fputs("\ SHOW COMMENT displays the comment character.\n", stderr); break; case KW_SILENT: fputs("\ SHOW SILENT tells whether error and warning messages are disabled\n\ (not displayed on the screen).\n", stderr); break; case KW_TIMING: fputs("\ SHOW TIMING tells whether the elapsed time required to process a\n\ command is displayed when the command finishes.\n", stderr); break; case KW_WARNING: fputs("\ SHOW WARNING tells whether warning messages are displayed on the\n\ screen.\n", stderr); break; } } /******************************************************************* * NAME * do_help * DESCRIPTION * execute the HELP command * RETURN VALUE * none */ static void do_help(char * pszKeyword_in) { static char szGeneric_s[] = "Type HELP <command> for more help on a particular command\n"; char * pszProg; char * pszFile; if ((pszCmdProgramName_g == NULL) || (*pszCmdProgramName_g == NUL)) { pszProg = "the program"; pszFile = "cmd"; } else { pszProg = pszCmdProgramName_g; pszFile = pszCmdProgramName_g; } switch (lookupCmdKeyword(pszKeyword_in, asCommandTable_m, iCommandTableSize_m, "")) { case CMD_NULL: fputs("\n\ chdir (or cd) changes the current directory\n\ close closes the log file\n\ directory (or ls) lists the files in the current directory\n\ edit edits a file with your favorite editor\n\ help provides nice messages like this one\n\ load ...\n\ log opens a log file\n\ process processes one file to create another\n\ quit (or exit) exits the program\n\ save ...\n\ set sets a program parameter\n\ show shows the settings of one or more parameters\n\ system (or !) executes a command in a subshell\n\ take (or @) reads (\"takes\") commands from a file\n\ \n", stderr); fputs(szGeneric_s, stderr); break; case CMD_AMBIGUOUS: displayNumberedMessage(&sCmdAmbiguousKeyword_g, NULL, NULL, "HELP", pszKeyword_in); break; case CMD_INVALID: if (strcmp(pszKeyword_in, "!") == 0) goto help_system; if (strcmp(pszKeyword_in, "@") == 0) goto help_take; displayNumberedMessage(&sCmdBadKeyword_g, NULL, NULL, "HELP", pszKeyword_in); break; case CMD_HELP: /* ? - list of commands displayed */ fputs(szGeneric_s, stderr); break; case KW_CHDIR: fputs("\ CHDIR <pathname> changes the current directory. You can give a\n\ full path starting with a / (for example,\n\ \"/u/evan/pckimmo/englex/new\"); a path starting with ../ which\n\ indicates the directory above the current one; and so on.\n\ Directories are separated by the / character.\n", stderr); break; case KW_CLOSE: fputs("\ CLOSE closes the log file opened by a LOG command.\n", stderr); break; case KW_EDIT: fputs("\ EDIT <file> attempts to edit a file using the program indicated\n\ by the environment variable EDITOR. If this environment variable\n\ is not defined, then emacs is used to edit the file.\n", stderr); break; case KW_DIRECTORY: fputs("\ DIRECTORY lists the contents of the current directory.\n", stderr); break; case KW_HELP: fprintf(stderr, "\ HELP [<command-name>] displays a description of a command. If\n\ HELP is typed by itself, %s displays a list of commands with\n\ short descriptions of each command.\n", pszProg); break; case KW_LOAD: fputs("\ LOAD <filename> ... (has not been written)\n", stderr); break; case KW_LOG: fprintf(stderr, "\ LOG [<file>] opens a log file. If a filename is given on the\n\ same line as the LOG command, then that file is used for the log\n\ file. Any previously existing file with the same name will be\n\ overwritten. If no filename is provided, then the file %s.log\n\ in the current directory is used for the log file.\n\ \n\ Use CLOSE to stop recording in a log file. If a LOG command is\n\ given when a log file is already open, then the earlier log file\n\ is closed before the new log file is opened.\n", pszFile); break; case KW_PROCESS: fputs("\ PROCESS <infile> <outfile> processes the input file to create the\n\ output file.\n", stderr); break; case KW_QUIT: fputs("\ Either EXIT or QUIT terminates the program.\n", stderr); break; case KW_SAVE: fputs("\ SAVE <filename> ... (has not been written)\n", stderr); break; case KW_SET: do_help_set( strtok(NULL, szWhitespace_m) ); break; case KW_SHOW: do_help_show( strtok(NULL, szWhitespace_m) ); break; case KW_SYSTEM: help_system: fprintf(stderr, "\ SYSTEM [<command>] allows the user to execute an operating system\n\ command (such as listing the files in the current directory) from\n\ within %s. If no system-level command is given on the\n\ line with the SYSTEM command, then %s is pushed into the\n\ background and a new system command processor (shell) is started.\n\ Control is usually returned to %s in this case by typing\n\ EXIT as the operating system command.\n\ \n\ ! (exclamation point) is a synonym for SYSTEM.\n", pszProg, pszProg, pszProg); break; case KW_TAKE: help_take: fprintf(stderr, "\ TAKE [<file>] redirects command input to the specified file.\n\ \n\ The default filetype extension for TAKE is \".tak\", and the\n\ default filename is \"%s.tak\" (without the quotation marks,\n\ of course).\n\ \n\ TAKE files can be nested three deep. That is, the user types\n\ TAKE file1, file1 contains the command TAKE file2, and file2 has\n\ the command TAKE file3.\n\ It would be an error for file3 to contain a TAKE command. This\n\ should not prove to be a serious limitation.\n", pszFile); break; } } /******************************************************************* * NAME * do_set * DESCRIPTION * execute the SET command * RETURN VALUE * none */ static void do_set(char * pszKeyword_in) { char * pszArg; char * p; unsigned uiVal; switch (lookupCmdKeyword(pszKeyword_in, asSetTable_m, iSetTableSize_m, "")) { case CMD_NULL: displayNumberedMessage(&sCmdMissingKeyword_g, NULL, NULL, "SET"); break; case CMD_AMBIGUOUS: displayNumberedMessage(&sCmdAmbiguousKeyword_g, NULL, NULL, "SET", pszKeyword_in); break; case CMD_INVALID: displayNumberedMessage(&sCmdBadKeyword_g, NULL, NULL, "SET", pszKeyword_in); break; case CMD_HELP: /* ? */ fprintf(stderr, "Type HELP SET for more help\n"); break; case KW_CODE: pszArg = strtok(NULL, szWhitespace_m); if ((pszArg == NULL) || (*pszArg == NUL)) displayNumberedMessage(&sCmdMissingArgument_g, NULL, NULL, "SET CODE"); else { uiVal = strtoul(pszArg, &p, 0); if ((*p != NUL) || (uiVal > 255)) { displayNumberedMessage(&sCmdBadArgument_g, NULL, NULL, "SET CODE", pszArg); } else uiCode_m = uiVal; } break; case KW_COMMENT: pszArg = strtok(NULL, szWhitespace_m); if ((pszArg == NULL) || (*pszArg == NUL)) displayNumberedMessage(&sCmdMissingArgument_g, NULL, NULL, "SET COMMENT"); else cCommentMarker_m = *pszArg; break; case KW_SILENT: pszArg = strtok(NULL, szWhitespace_m); switch (lookupCmdKeyword(pszArg, asOnOffTable_m, iOnOffTableSize_m, "")) { case CMD_NULL: displayNumberedMessage(&sCmdMissingKeyword_g, NULL, NULL, "SET SILENT"); break; case CMD_AMBIGUOUS: displayNumberedMessage(&sCmdAmbiguousKeyword_g, NULL, NULL, "SET SILENT", pszArg); break; case CMD_INVALID: displayNumberedMessage(&sCmdBadKeyword_g, NULL, NULL, "SET SILENT", pszArg); break; case CMD_HELP: break; case KW_ON: bCmdSilentMessages_g = TRUE; break; case KW_OFF: bCmdSilentMessages_g = FALSE; break; } break; case KW_TIMING: pszArg = strtok(NULL, szWhitespace_m); switch (lookupCmdKeyword(pszArg, asOnOffTable_m, iOnOffTableSize_m, "")) { case CMD_NULL: displayNumberedMessage(&sCmdMissingKeyword_g, NULL, NULL, "SET TIMING"); break; case CMD_AMBIGUOUS: displayNumberedMessage(&sCmdAmbiguousKeyword_g, NULL, NULL, "SET TIMING", pszArg); break; case CMD_INVALID: displayNumberedMessage(&sCmdBadKeyword_g, NULL, NULL, "SET TIMING", pszArg); break; case CMD_HELP: break; case KW_ON: bTiming_m = TRUE; break; case KW_OFF: bTiming_m = FALSE; break; } break; case KW_WARNING: pszArg = strtok(NULL, szWhitespace_m); switch (lookupCmdKeyword(pszArg, asOnOffTable_m, iOnOffTableSize_m, "")) { case CMD_NULL: displayNumberedMessage(&sCmdMissingKeyword_g, NULL, NULL, "SET SILENT"); break; case CMD_AMBIGUOUS: displayNumberedMessage(&sCmdAmbiguousKeyword_g, NULL, NULL, "SET SILENT", pszArg); break; case CMD_INVALID: displayNumberedMessage(&sCmdBadKeyword_g, NULL, NULL, "SET SILENT", pszArg); break; case CMD_HELP: break; case KW_ON: bCmdShowWarnings_g = TRUE; break; case KW_OFF: bCmdShowWarnings_g = FALSE; break; } break; } } /******************************************************************* * NAME * do_show * DESCRIPTION * execute the SHOW command * RETURN VALUE * none */ static void do_show(char * pszKeyword_in) { switch (lookupCmdKeyword(pszKeyword_in, asSetTable_m, iSetTableSize_m, "")) { case CMD_NULL: fprintf(stderr, "CODE is %x\n", uiCode_m); if (cCommentMarker_m) fprintf(stderr, "COMMENT is %c\n", cCommentMarker_m); else fprintf(stderr, "COMMENT is not set\n"); fprintf(stderr, "SILENT is %s\n", bCmdSilentMessages_g ? "ON" : "OFF"); fprintf(stderr, "TIMING is %s\n", bCmdSilentMessages_g ? "ON" : "OFF"); fprintf(stderr, "WARNING is %s\n", bCmdShowWarnings_g ? "ON" : "OFF"); break; case CMD_AMBIGUOUS: displayNumberedMessage(&sCmdAmbiguousKeyword_g, NULL, NULL, "SHOW", pszKeyword_in); break; case CMD_INVALID: displayNumberedMessage(&sCmdBadKeyword_g, NULL, NULL, "SHOW", pszKeyword_in); break; case CMD_HELP: fprintf(stderr, "Type HELP SHOW for more help\n"); break; case KW_CODE: fprintf(stderr, "CODE is %x\n", uiCode_m); break; case KW_COMMENT: if (cCommentMarker_m) fprintf(stderr, "COMMENT is %c\n", cCommentMarker_m); else fprintf(stderr, "COMMENT is not set\n"); break; case KW_SILENT: fprintf(stderr, "SILENT is %s\n", bCmdSilentMessages_g ? "ON" : "OFF"); break; case KW_TIMING: fprintf(stderr, "TIMING is %s\n", bCmdSilentMessages_g ? "ON" : "OFF"); break; case KW_WARNING: fprintf(stderr, "WARNING is %s\n", bCmdShowWarnings_g ? "ON" : "OFF"); break; } } /******************************************************************* * NAME * do_process * DESCRIPTION * process the input file to create the output file * RETURN VALUE * none */ static void do_process(char * pszInput_in, char * pszOutput_in) { time_t iTime = time(NULL); int c; FILE * pInputFP; char * pszInputFile; char * pszOutputFile; if (pszInput_in == NULL) { displayNumberedMessage(&sCmdMissingInputFile_g, NULL, NULL, "PROCESS"); return; } if (pszOutput_in == NULL) { displayNumberedMessage(&sCmdMissingOutputFile_g, NULL, NULL, "PROCESS"); return; } if ( wantCmdHelp(pszInput_in, szProcessUsage_m) || wantCmdHelp(pszOutput_in, szProcessUsage_m) ) return; if (getCmdTakeLevel() != 0) { pszInputFile = buildAdjustedFilename(pszInput_in, getCmdTakeFile(), NULL); pszOutputFile = buildAdjustedFilename(pszOutput_in, getCmdTakeFile(), NULL); } else { pszInputFile = duplicateString(pszInput_in); pszOutputFile = duplicateString(pszOutput_in); } pInputFP = fopen( pszInputFile, "rb"); if (pInputFP == NULL) { displayNumberedMessage(&sCmdBadInputFile_g, NULL, NULL, pszInputFile, "PROCESS"); } else { pCmdOutputFP_g = fopen( pszOutputFile, "wb" ); if (pCmdOutputFP_g == NULL) { displayNumberedMessage(&sCmdBadOutputFile_g, NULL, NULL, pszOutputFile, "PROCESS"); } else { if (bTiming_m) startCmdTiming(); if (pCmdLogFP_g != NULL) { fprintf(pCmdLogFP_g, "Processing %s to create %s (log = %s) at %s", pszInput_in, pszOutput_in, pszCmdLogFile_g ? pszCmdLogFile_g : "?", ctime(&iTime)); } while ((c = fgetc(pInputFP)) != EOF) { c ^= uiCode_m; fputc(c, pCmdOutputFP_g); } fclose(pCmdOutputFP_g); pCmdOutputFP_g = NULL; if (bTiming_m) { stopCmdTiming(); showCmdTiming(); } } fclose(pInputFP); } freeMemory( pszInputFile ); freeMemory( pszOutputFile ); } /******************************************************************* * NAME * do_load * DESCRIPTION * execute a LOAD command * RETURN VALUE * none */ static void do_load(char * pszFilename_in) { if ((pszFilename_in == NULL) || (*pszFilename_in == NUL)) { displayNumberedMessage(&sCmdMissingInputFile_g, NULL, NULL, "LOAD"); return; } /* left as an exercise for the reader :-) */ fprintf(stderr, "load %s is not implemented\n", pszFilename_in); } /******************************************************************* * NAME * do_save * DESCRIPTION * execute a SAVE command * RETURN VALUE * none */ static void do_save(char * pszFilename_in) { if ((pszFilename_in == NULL) || (*pszFilename_in == NUL)) { displayNumberedMessage(&sCmdMissingOutputFile_g, NULL, NULL, "SAVE"); return; } /* left as an exercise for the reader :-) */ fprintf(stderr, "save %s is not implemented\n", pszFilename_in); } /******************************************************************* * NAME * do_command * DESCRIPTION * read and execute a command * RETURN VALUE * TRUE (1) to continue, FALSE (0) to stop the program */ static int do_command() { char * pszCommand; char * pszSaved; char * pszArg; char * p; pszCommand = getCmdString(NULL, szPrompt_m, cCommentMarker_m); if ((pszCommand == NULL) || (*pszCommand == NUL)) return 1; /* ignore empty commands */ /* * save a copy of the command line */ pszSaved = duplicateString(pszCommand + strspn(pszCommand, szWhitespace_m)); /* * parse the first keyword of the command */ pszArg = strtok(pszCommand, szWhitespace_m); switch (lookupCmdKeyword(pszArg, asCommandTable_m, iCommandTableSize_m, "")) { case CMD_NULL: break; /* ignore empty commands */ case CMD_AMBIGUOUS: displayNumberedMessage(&sCmdAmbiguous_g, NULL, NULL, pszCommand); break; case CMD_INVALID: if (*pszArg == '!') { pszArg = pszSaved + 1; pszArg += strspn(pszArg, szWhitespace_m); doCmdSystem( pszArg ); } else if (*pszArg == '@') { if (pszArg[1] == NUL) pszArg = strtok(NULL, szWhitespace_m); else ++pszArg; doCmdTake( pszArg ); } else if (getCmdTakeLevel() != 0) { displayNumberedMessage(&sCmdErrorInTake_g, NULL, NULL, pszArg); closeCmdTake(); } else displayNumberedMessage(&sCmdInvalid_g, NULL, NULL, pszArg); break; case CMD_HELP: /* ? - list of commands displayed */ fprintf(stderr, "Type HELP for more help\n"); break; case KW_CHDIR: pszArg = strtok(NULL, szWhitespace_m); doCmdChdir( pszArg ); break; case KW_CLOSE: doCmdClose(); break; case KW_EDIT: pszArg = strtok(NULL, szWhitespace_m); if (getCmdTakeLevel() != 0) pszArg = buildAdjustedFilename(pszArg, getCmdTakeFile(), NULL); doCmdEdit( pszArg ); freeMemory( pszArg ); break; case KW_DIRECTORY: pszArg = pszSaved; pszArg += strcspn(pszArg, szWhitespace_m); pszArg += strspn(pszArg, szWhitespace_m); doCmdDirectory( pszArg ); break; case KW_HELP: do_help( strtok(NULL, szWhitespace_m) ); break; case KW_LOAD: pszArg = strtok(NULL, szWhitespace_m); pszArg = setCmdFilename( pszArg, "settings.ini", ".ini"); if (getCmdTakeLevel() != 0) { p = buildAdjustedFilename(pszArg, getCmdTakeFile(), NULL); freeMemory( pszArg ); pszArg = p; } do_load( pszArg ); freeMemory( pszArg ); break; case KW_LOG: doCmdLog( strtok(NULL, szWhitespace_m) ); break; case KW_PROCESS: pszArg = strtok(NULL,szWhitespace_m); do_process(pszArg, strtok(NULL, szWhitespace_m)); break; case KW_QUIT: /* QUIT or EXIT */ while (closeCmdTake()) ; freeMemory(pszSaved); return 0; case KW_SAVE: pszArg = strtok(NULL, szWhitespace_m); pszArg = setCmdFilename( pszArg, "settings.ini", ".ini"); if (getCmdTakeLevel() != 0) { p = buildAdjustedFilename(pszArg, getCmdTakeFile(), NULL); freeMemory( pszArg ); pszArg = p; } do_save( pszArg ); freeMemory( pszArg ); break; case KW_SET: do_set( strtok(NULL, szWhitespace_m) ); break; case KW_SHOW: do_show( strtok(NULL, szWhitespace_m) ); break; case KW_SYSTEM: pszArg = pszSaved; pszArg += strcspn(pszArg, szWhitespace_m); pszArg += strspn(pszArg, szWhitespace_m); doCmdSystem( pszArg ); break; case KW_TAKE: pszArg = strtok(NULL, szWhitespace_m); if (getCmdTakeLevel() != 0) pszArg = buildAdjustedFilename(pszArg, getCmdTakeFile(), NULL); doCmdTake( pszArg ); freeMemory( pszArg ); break; } freeMemory(pszSaved); return 1; } /******************************************************************* * NAME * main * DESCRIPTION * the main procedure for this program * RETURN VALUE * 1 to indicate successful execution of the program */ int main(int argc, char ** argv) { char * p; /* * establish the program basename */ pszCmdProgramName_g = strrchr(argv[0], '/'); if (pszCmdProgramName_g == NULL) pszCmdProgramName_g = argv[0]; else ++pszCmdProgramName_g; if ((pszCmdProgramName_g == NULL) || (*pszCmdProgramName_g == NUL)) pszCmdProgramName_g = "unknown"; pszCmdProgramName_g = duplicateString(pszCmdProgramName_g); if ((p = strrchr(pszCmdProgramName_g, '.')) != NULL) *p = NUL; /* * set up for error or SIGINT trapping */ if (setjmp(sCmdJmpBuf_g) != 0) { fputs("\nRETURNING TO PC-KIMMO COMMAND PROCESSING\n\n", stderr); } else { #ifdef USE_SIGNAL #ifdef SIGINT signal( SIGINT, handleCmdSigint ); #endif #endif } /* * read and execute commands until QUIT or EXIT */ fprintf(stderr, "%s - test program for the CMD function library\n", argv[0]); while (do_command()) ; return 1; }
This document was generated on 20 March 2003 using texi2html 1.56k.