home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Oakland CPM Archive
/
oakcpm.iso
/
cpm
/
comnd
/
comnd004.ark
/
TEST.C
< prev
Wrap
C/C++ Source or Header
|
1986-06-17
|
12KB
|
400 lines
/* The following is a test program for a subroutine set which provides
a simple emulation of the TOPS-20 COMND JSYS for C programs. This
program tests some of the basic features, and illustrates how the
subroutine package is used. */
#include "comnd.h" /* Include interface definitions */
/* for the COMND package */
#include "stdio.h" /* Include standard system defn's */
#include "setjmp.h" /* Include defn for the setjmp/longjump */
/* facility of the C language */
/* Declare forward routines that our program uses; mainly those routines
which are included in the command dispatch table. Since they will be in
the table, they must be defined. */
int datcmd(); /* The DATE command */
int exicmd(); /* The EXIT command */
int hlpcmd(); /* The HELP command */
int numcmd(); /* The NUMBER command */
int uicmd(); /* Unimplemented command */
/* Declare various simple variables our program uses. */
char Atmbuf[100] = {0}; /* Atom buffer used by CSB */
jmp_buf Topenv = {0}; /* Setjump buffer used in command
parsing. */
char Txtbuf[100] = {0}; /* Text buffer used by CSB (later) */
/* Define our command table and dispatch table. The command table is a
table of pointers to strings; these strings do not have to be in any
order; but remember they are printed (for help) in the order given
here. */
/* Note that in the command table, only a few of the entries are
reasonable. The rest of the keywords are in the table to illustrate
the way that keywords are matched by the COMND subroutines. */
char *Cmdtbl[] = { /* Command keyword table */
"ABLE",
"BAKER",
"BARKER",
"BASKET",
"CHANCELLOR",
"CHESTER",
"DATE",
"DOG",
"EXIT",
"HELP",
"NUMBER",
NULL /* The table ends with a null */
};
int (*Cmddsp[])() = { /* Dispatch table for commands */
uicmd, /* ABLE */
uicmd, /* BAKER */
uicmd, /* BARKER */
uicmd, /* BASKET */
uicmd, /* CHANCELLOR */
uicmd, /* CHESTER */
datcmd, /* DATE */
uicmd, /* DOG */
exicmd, /* EXIT */
hlpcmd, /* HELP */
numcmd /* NUMBER */
};
/* Define our Command State Block. A program may have any number of
these, and typically have a couple (one for main level commands and
another for subcommands, etc.). This program only uses one, because
it is not very complex. */
CSB Topcsb = {0, /* Flags to pass to COMND subroutine */
0, /* Flags returned by COMND */
&Topenv, /* Address of setjmp buffer; used in
transfering control if a reparse
is necessary */
0, /* Input designator (ignored) */
0, /* Output designator (ignored) */
"TEST> ", /* Prompt string */
&Txtbuf, /* Address of text buffer */
100, /* Size of text buffer (bytes) */
&Atmbuf, /* Address of atom buffer */
100, /* Size of atom buffer (bytes) */
0}; /* The rest of the block is used for
returned values and does not have
to be initialized here */
/* Define the various Command Function Blocks that we will use. Each
function block defines something to be parsed. The first definition is
expanded with comments; the rest are simply defined. */
CFB Cmdcfb = {_CMKEY, /* Function code (_CMKEY=keyword) */
_CFDPP|_CFHPP, /* Flags; _CFDPP indicates that
we've supplied a default string;
_CFHPP indicates that we've
supplied our own help text to be
used in addition to the standard
help. _CFSDH would suppress the
standard help as well. */
0, /* This would be an address of another
CFB to be used in satisfying the
parse. No alternatives here */
&Cmdtbl, /* Data for the function; addr of
keyword table, here. */
"Command, ", /* Help text that we supply */
"BASKET" /* Default string. */
};
/* CFB for HELP... this illustrates how CFBs can be chained to give
alternative parse paths. */
CFB Hlpcfb = {_CMTOK, _CFHPP|_CFSDH, &Cmdcfb, "*",
"\"*\" for help on all topics", 0};
/* Initialization CFB */
CFB Inicfb = {_CMINI, 0, 0, 0, 0, 0};
/* CFB for guide words */
CFB Noicfb = {_CMNOI, 0, 0, 0, 0, "guide words"};
/* CFB for confirmation */
CFB Cfmcfb = {_CMCFM, 0, 0, 0, 0, 0};
/* CFB for date parse */
CFB Datcfb = {_CMDAT, _CFDTD|_CFDTT, 0, 0, 0, 0};
/* CFB for decimal number parse */
CFB Numcfb = {_CMNUM, 0, 0, 10, 0, 0};
/*
*/
/* The main routine. */
main()
{
IND int i; /* Scratch */
IND char **kptr; /* Keyword ptr ptr */
/* Enter command loop. */
while (TRUE)
{
/* The first part of COMND parsing is to initialize the parse. This is
done with a CFB with function code of _CFINI */
COMND (&Topcsb, &Inicfb); /* Init the parse */
/* Call setjmp to mark the point where a reparse of the command string would
take place. Since we've supplied this setjmp buffer address to COMND (by
putting its address in our CSB), COMND will transfer control here whenever
a reparse should take place. If the setjmp mechanism is not used, the
program must always check for a return code of _CRRPT, indicating that
a reparse is necessary. The setjmp mechanism is the far simpler method. */
setjmp (Topenv); /* Trap reparse */
/* Now parse a command keyword. This is done by calling COMND with the
appropriate command function block. */
if (!COMNDi (&Topcsb, &Cmdcfb)) /* Parse a command */
continue; /* continue if failed. (see the */
/* routine COMNDI() below) */
/* Now determine what keyword was parsed. The return value (in CSB_RVL of
the command state block) is the address of the keyword table entry which
was parsed. Thus it is a pointer to a pointer to the keyword. */
kptr = (char **) (Topcsb.CSB_RVL._ADR);
/* Get the table entry address */
i = kptr - &Cmdtbl[0]; /* Get the command table index */
/* i now has the command index; simply dispatch via the command dispatch
table to the appropriate processing routine. */
(*Cmddsp[i])(); /* Call the routine */
/* End of command loop. */
}
}
/*
*/
/* datcmd - the DATE command */
datcmd ()
{
IND int id,it,m,d,y,mm,hh; /* Date/time values */
IND int *rslptr; /* Result pointer */
/* Issue a call to our "noise" subroutine (below) to parse guide words. */
if (!noise("is")) /* Do guide word parse */
return; /* And return if it failed */
/* Parse the command argument */
if (!COMNDi(&Topcsb, &Datcfb)) /* Do COMND call and check failure */
return;
/* Issue call to our "confrm" routine to confirm the command. */
if (!confrm()) /* Call our general confirm routine */
return; /* If not confirmed, just return. */
rslptr = &Atmbuf[0];
id = rslptr[0]; /* Get results */
it = rslptr[1];
cvided (id, it, &m, &d, &y, &hh, &mm);
printf ("Returned %02d/%02d/%04d %02d:%02d\n", m, d, y, hh, mm);
}
/*
*/
/* exicmd - the EXIT command */
exicmd ()
{
/* Issue a call to our "noise" subroutine (below) to parse guide words. */
if (!noise("program")) /* Do guide word parse */
return; /* And return if it failed */
/* Issue call to our "confrm" routine to confirm the command. */
if (!confrm()) /* Call our general confirm routine */
return; /* If not confirmed, just return. */
exit(); /* Exit the program. */
}
/*
*/
/* hlpcmd - the HELP command */
/* This command illustrates how COMND is used to parse one of multiple
choices; here we either parse the token "*" or a command keyword. */
hlpcmd ()
{
char **kptr; /* Points to keyword */
char *aptr; /* Points to argument */
/* Collect the help argument, after giving appropriate guide string */
if (!noise ("on subject")) /* Give guide string */
return; /* return if it failed */
/* Parse the command argument. */
if (!COMNDi(&Topcsb, &Hlpcfb)) /* Do COMND call and check failure */
return;
/* Since we supplied alternate CFBs in our COMND call, we have to see which
one matched the input, and process accordingly. Here "process" is simply
to set a pointer to the text we are going to say we can't give help for */
if (Topcsb.CSB_CFB == &Hlpcfb) /* If matched our token */
aptr = "*"; /* Set pointer to token string. */
else /* Otherwise */
{
kptr = (char **) Topcsb.CSB_RVL._ADR;
/* Get ptr to keyword pointer */
aptr = *kptr; /* Get addr of string */
}
if (!confrm()) /* Call our general confirm routine */
return; /* If not confirmed, just return. */
/* Now we've got the keyword; this is only a test routine, show the thing
parsed and say we can't give help for it. */
printf ("Sorry, can not give help for ");
printf (aptr);
printf ("\n");
}
/*
*/
/* numcmd - the NUMBER command */
numcmd ()
{
IND int num; /* Number */
if (!noise ("to print")) /* Get/give guide string */
return; /* Return if invalid */
if (!COMNDi (&Topcsb, &Numcfb)) /* If not ok */
return;
/* Extract the number from the returned value field in the CSB; then go
on to confirm the command. */
num = Topcsb.CSB_RVL._INT; /* Get the number */
if (!confrm()) /* Call our general confirm routine */
return; /* If not confirmed, just return. */
printf ("Number is %d\n", num); /* Print the number, for show */
}
/*
*/
/* uicmd - unimplemented or silly commands */
uicmd ()
{
if (!noise ("nothing")) /* Give random guide string */
return; /* Return if bad parse of it */
if (!confrm()) /* Call our general confirm routine */
return; /* If not confirmed, just return. */
printf ("This command is not implemented.\n");
}
/*
*/
/* noise - parses a guide string. Called with the address of the expected
guide string; without the parentheses, of course. */
noise (str)
char *str; /* Address of string */
{
Noicfb.CFB_DEF = str; /* Store the string pointer in
the guide word CFB */
return (COMNDi(&Topcsb, &Noicfb)); /* Do parse and return the result */
}
/*
*/
/* confrm - get confirmation (call COMND for confirm) */
/* Returns TRUE if OK confirmation; FALSE if not. */
confrm ()
{
if (COMNDi (&Topcsb, &Cfmcfb)) /* Get confirmation */
return (TRUE); /* Give OK return if success */
printf (" ?Not confirmed\n"); /* Give another error msg */
return (FALSE); /* Return bad status. */
}
/*
*/
/* COMNDi - interface to the COMND() library routine, giving a message if
a parse error occurs. Returns TRUE or FALSE depending on success */
int COMNDi (CSBptr, CFBptr)
CSB *CSBptr; /* Address of command state block */
CFB *CFBptr; /* Address of command function block */
{
IND int i; /* A counter */
IND char *sptr; /* A string pointer */
if (COMND(CSBptr, CFBptr) == _CROK) /* If successful parse */
return (TRUE); /* then give good return */
sptr = &CSBptr->CSB_BUF[CSBptr->CSB_PRS]; /* Get addr of unrecognized input */
i = CSBptr->CSB_FLN - CSBptr->CSB_PRS; /* Get # of chars unrecognized */
printf (" ??Invalid- Can not recognize \"");
while (i--)
putchar (*sptr++); /* Print the bad string */
printf ("\"... use ? here.\n"); /* Tell him how to proceed. */
return (FALSE); /* Give bad return */
}