home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / cpm / comnd / comnd004.ark / TEST.C < prev   
Encoding:
C/C++ Source or Header  |  1986-06-17  |  11.4 KB  |  400 lines

  1.  
  2. /* The following is a test program for a subroutine set which provides
  3.    a simple emulation of the TOPS-20 COMND JSYS for C programs.  This
  4.    program tests some of the basic features, and illustrates how the
  5.    subroutine package is used. */
  6.  
  7. #include "comnd.h"            /* Include interface definitions */
  8.                     /* for the COMND package */
  9. #include "stdio.h"            /* Include standard system defn's */
  10. #include "setjmp.h"            /* Include defn for the setjmp/longjump */
  11.                     /* facility of the C language */
  12.  
  13. /* Declare forward routines that our program uses; mainly those routines
  14.    which are included in the command dispatch table.  Since they will be in
  15.    the table, they must be defined. */
  16.  
  17.    int        datcmd();        /* The DATE command */
  18.    int        exicmd();        /* The EXIT command */
  19.    int        hlpcmd();        /* The HELP command */
  20.    int        numcmd();        /* The NUMBER command */
  21.    int        uicmd();        /* Unimplemented command */
  22.  
  23. /* Declare various simple variables our program uses. */
  24.  
  25.  
  26. char        Atmbuf[100] = {0};    /* Atom buffer used by CSB */
  27. jmp_buf        Topenv = {0};        /* Setjump buffer used in command
  28.                        parsing. */
  29. char        Txtbuf[100] = {0};    /* Text buffer used by CSB (later) */
  30.  
  31.  
  32. /* Define our command table and dispatch table.  The command table is a
  33.    table of pointers to strings; these strings do not have to be in any
  34.    order; but remember they are printed (for help) in the order given
  35.    here. */
  36.  
  37. /* Note that in the command table, only a few of the entries are
  38.    reasonable.  The rest of the keywords are in the table to illustrate
  39.    the way that keywords are matched by the COMND subroutines. */
  40.  
  41. char        *Cmdtbl[] = {        /* Command keyword table */
  42.                 "ABLE",
  43.                 "BAKER",
  44.                 "BARKER",
  45.                 "BASKET",
  46.                 "CHANCELLOR",
  47.                 "CHESTER",
  48.                 "DATE",
  49.                 "DOG",
  50.                 "EXIT",
  51.                 "HELP",
  52.                 "NUMBER",
  53.                 NULL    /* The table ends with a null */
  54.                 };
  55.  
  56. int        (*Cmddsp[])() = {    /* Dispatch table for commands */
  57.             uicmd,        /* ABLE */
  58.             uicmd,        /* BAKER */
  59.             uicmd,        /* BARKER */
  60.             uicmd,        /* BASKET */
  61.             uicmd,        /* CHANCELLOR */
  62.             uicmd,        /* CHESTER */
  63.             datcmd,        /* DATE */
  64.             uicmd,        /* DOG */
  65.             exicmd,        /* EXIT */
  66.             hlpcmd,        /* HELP */
  67.             numcmd        /* NUMBER */
  68.                 };
  69.  
  70.  
  71. /* Define our Command State Block.  A program may have any number of
  72.    these, and typically have a couple (one for main level commands and
  73.    another for subcommands, etc.).  This program only uses one, because
  74.    it is not very complex. */
  75.  
  76.  
  77.    CSB        Topcsb = {0,        /* Flags to pass to COMND subroutine */
  78.               0,        /* Flags returned by COMND */
  79.               &Topenv,    /* Address of setjmp buffer; used in
  80.                          transfering control if a reparse
  81.                        is necessary */
  82.               0,        /* Input designator (ignored) */
  83.               0,         /* Output designator (ignored) */
  84.               "TEST> ",    /* Prompt string */
  85.               &Txtbuf,    /* Address of text buffer */
  86.               100,        /* Size of text buffer (bytes) */
  87.               &Atmbuf,    /* Address of atom buffer */
  88.               100,        /* Size of atom buffer (bytes) */
  89.               0};        /* The rest of the block is used for
  90.                          returned values and does not have
  91.                        to be initialized here */
  92.  
  93.  
  94. /* Define the various Command Function Blocks that we will use.  Each
  95.    function block defines something to be parsed.  The first definition is
  96.    expanded with comments; the rest are simply defined. */
  97.  
  98.  
  99.    CFB        Cmdcfb = {_CMKEY,    /* Function code (_CMKEY=keyword) */
  100.               _CFDPP|_CFHPP, /* Flags;  _CFDPP indicates that
  101.                           we've supplied a default string;
  102.                         _CFHPP indicates that we've
  103.                         supplied our own help text to be
  104.                         used in addition to the standard
  105.                         help.  _CFSDH would suppress the
  106.                         standard help as well. */
  107.                0,        /* This would be an address of another
  108.                           CFB to be used in satisfying the
  109.                        parse.  No alternatives here */
  110.                &Cmdtbl,    /* Data for the function; addr of
  111.                           keyword table, here. */
  112.                "Command, ",    /* Help text that we supply */
  113.                "BASKET"    /* Default string. */
  114.                };
  115.  
  116.     /* CFB for HELP... this illustrates how CFBs can be chained to give
  117.        alternative parse paths. */
  118. CFB        Hlpcfb = {_CMTOK, _CFHPP|_CFSDH, &Cmdcfb, "*",
  119.               "\"*\" for help on all topics", 0};
  120.  
  121.     /* Initialization CFB */
  122. CFB        Inicfb = {_CMINI, 0, 0, 0, 0, 0};
  123.  
  124.     /* CFB for guide words */
  125. CFB        Noicfb = {_CMNOI, 0, 0, 0, 0, "guide words"};
  126.  
  127.     /* CFB for confirmation */
  128. CFB        Cfmcfb = {_CMCFM, 0, 0, 0, 0, 0};
  129.  
  130.     /* CFB for date parse */
  131. CFB        Datcfb = {_CMDAT, _CFDTD|_CFDTT, 0, 0, 0, 0};
  132.  
  133.     /* CFB for decimal number parse */
  134. CFB        Numcfb = {_CMNUM, 0, 0, 10, 0, 0};
  135. /*
  136.  
  137. */
  138.  
  139. /* The main routine. */
  140.  
  141.  
  142. main()
  143.  
  144. {
  145. IND    int    i;            /* Scratch */
  146. IND    char    **kptr;            /* Keyword ptr ptr */
  147.  
  148.  
  149. /* Enter command loop. */
  150.  
  151. while (TRUE)
  152.     {
  153.  
  154. /* The first part of COMND parsing is to initialize the parse.  This is
  155.    done with a CFB with function code of _CFINI */
  156.  
  157.     COMND (&Topcsb, &Inicfb);        /* Init the parse */
  158.  
  159.  
  160. /* Call setjmp to mark the point where a reparse of the command string would
  161.    take place.  Since we've supplied this setjmp buffer address to COMND (by
  162.    putting its address in our CSB), COMND will transfer control here whenever
  163.    a reparse should take place.  If the setjmp mechanism is not used, the
  164.    program must always check for a return code of _CRRPT, indicating that
  165.    a reparse is necessary.  The setjmp mechanism is the far simpler method. */
  166.  
  167.     setjmp (Topenv);            /* Trap reparse */
  168.  
  169. /* Now parse a command keyword.  This is done by calling COMND with the
  170.    appropriate command function block. */
  171.  
  172.     if (!COMNDi (&Topcsb, &Cmdcfb))    /* Parse a command */
  173.     continue;            /*  continue if failed.  (see the */
  174.                     /*  routine COMNDI() below) */
  175.  
  176. /* Now determine what keyword was parsed.  The return value (in CSB_RVL of
  177.    the command state block) is the address of the keyword table entry which
  178.    was parsed.  Thus it is a pointer to a pointer to the keyword. */
  179.  
  180.     kptr = (char **) (Topcsb.CSB_RVL._ADR);
  181.                     /* Get the table entry address */
  182.     i = kptr - &Cmdtbl[0];        /* Get the command table index */
  183.  
  184.  
  185. /* i now has the command index; simply dispatch via the command dispatch
  186.    table to the appropriate processing routine. */
  187.  
  188.     (*Cmddsp[i])();            /* Call the routine */
  189.  
  190. /* End of command loop. */
  191.  
  192.     }
  193.  
  194. }
  195. /*
  196.  
  197. */
  198.  
  199. /* datcmd - the DATE command */
  200.  
  201. datcmd ()
  202.  
  203. {
  204. IND    int    id,it,m,d,y,mm,hh;    /* Date/time values */
  205. IND    int    *rslptr;        /* Result pointer */
  206.  
  207. /* Issue a call to our "noise" subroutine (below) to parse guide words. */
  208.  
  209. if (!noise("is"))            /* Do guide word parse */
  210.     return;                /* And return if it failed */
  211.  
  212. /* Parse the command argument */
  213.  
  214. if (!COMNDi(&Topcsb, &Datcfb))        /* Do COMND call and check failure */
  215.     return;
  216.  
  217. /* Issue call to our "confrm" routine to confirm the command. */
  218.  
  219. if (!confrm())                /* Call our general confirm routine */
  220.     return;                /* If not confirmed, just return. */
  221.  
  222.  
  223. rslptr = &Atmbuf[0];
  224. id = rslptr[0];                /* Get results */
  225. it = rslptr[1];
  226. cvided (id, it, &m, &d, &y, &hh, &mm);
  227. printf ("Returned %02d/%02d/%04d %02d:%02d\n", m, d, y, hh, mm);
  228.  
  229. }
  230. /*
  231.  
  232. */
  233.  
  234. /* exicmd - the EXIT command */
  235.  
  236. exicmd ()
  237.  
  238. {
  239. /* Issue a call to our "noise" subroutine (below) to parse guide words. */
  240.  
  241. if (!noise("program"))            /* Do guide word parse */
  242.     return;                /* And return if it failed */
  243.  
  244. /* Issue call to our "confrm" routine to confirm the command. */
  245.  
  246. if (!confrm())                /* Call our general confirm routine */
  247.     return;                /* If not confirmed, just return. */
  248.  
  249. exit();                    /* Exit the program. */
  250. }
  251. /*
  252.  
  253. */
  254.  
  255. /* hlpcmd - the HELP command */
  256.  
  257. /* This command illustrates how COMND is used to parse one of multiple
  258.    choices; here we either parse the token "*" or a command keyword. */
  259.  
  260. hlpcmd ()
  261.  
  262. {
  263. char        **kptr;            /* Points to keyword */
  264. char        *aptr;            /* Points to argument */
  265.  
  266. /* Collect the help argument, after giving appropriate guide string */
  267.  
  268. if (!noise ("on subject"))        /* Give guide string */
  269.     return;                /*  return if it failed */
  270.  
  271. /* Parse the command argument. */
  272.  
  273. if (!COMNDi(&Topcsb, &Hlpcfb))        /* Do COMND call and check failure */
  274.     return;
  275.  
  276. /* Since we supplied alternate CFBs in our COMND call, we have to see which
  277.    one matched the input, and process accordingly.  Here "process" is simply
  278.    to set a pointer to the text we are going to say we can't give help for */
  279.  
  280. if (Topcsb.CSB_CFB == &Hlpcfb)        /* If matched our token */
  281.     aptr = "*";                /* Set pointer to token string. */
  282. else                    /* Otherwise */
  283.     {
  284.     kptr = (char **) Topcsb.CSB_RVL._ADR;
  285.                     /* Get ptr to keyword pointer */
  286.     aptr = *kptr;            /* Get addr of string */
  287.     }
  288.  
  289. if (!confrm())                /* Call our general confirm routine */
  290.     return;                /* If not confirmed, just return. */
  291.  
  292. /* Now we've got the keyword; this is only a test routine, show the thing
  293.    parsed and say we can't give help for it. */
  294.  
  295. printf ("Sorry, can not give help for ");
  296. printf (aptr);
  297. printf ("\n");
  298. }
  299. /*
  300.  
  301. */
  302.  
  303. /* numcmd - the NUMBER command */
  304.  
  305. numcmd ()
  306.  
  307. {
  308. IND    int    num;            /* Number */
  309.  
  310. if (!noise ("to print"))        /* Get/give guide string */
  311.     return;                /* Return if invalid */
  312.  
  313. if (!COMNDi (&Topcsb, &Numcfb))        /* If not ok */
  314.     return;
  315.  
  316. /* Extract the number from the returned value field in the CSB; then go
  317.    on to confirm the command. */
  318.  
  319. num = Topcsb.CSB_RVL._INT;        /* Get the number */
  320.  
  321. if (!confrm())                /* Call our general confirm routine */
  322.     return;                /* If not confirmed, just return. */
  323.  
  324. printf ("Number is %d\n", num);        /* Print the number, for show */
  325. }
  326. /*
  327.  
  328. */
  329.  
  330. /* uicmd - unimplemented or silly commands */
  331.  
  332. uicmd ()
  333.  
  334. {
  335. if (!noise ("nothing"))            /* Give random guide string */
  336.     return;                /* Return if bad parse of it */
  337.  
  338. if (!confrm())                /* Call our general confirm routine */
  339.     return;                /* If not confirmed, just return. */
  340.  
  341. printf ("This command is not implemented.\n");
  342. }
  343. /*
  344.  
  345. */
  346.  
  347. /* noise - parses a guide string.  Called with the address of the expected
  348.    guide string; without the parentheses, of course. */
  349.  
  350. noise (str)
  351.  
  352. char        *str;            /* Address of string */
  353.  
  354. {
  355. Noicfb.CFB_DEF = str;            /* Store the string pointer in
  356.                        the guide word CFB */
  357. return (COMNDi(&Topcsb, &Noicfb));    /* Do parse and return the result */
  358. }
  359. /*
  360.  
  361. */
  362.  
  363. /* confrm - get confirmation (call COMND for confirm) */
  364.  
  365. /* Returns TRUE if OK confirmation; FALSE if not. */
  366.  
  367. confrm ()
  368.  
  369. {
  370. if (COMNDi (&Topcsb, &Cfmcfb))        /* Get confirmation */
  371.     return (TRUE);            /* Give OK return if success */
  372. printf (" ?Not confirmed\n");        /* Give another error msg */
  373. return (FALSE);                /* Return bad status. */
  374. }
  375. /*
  376.  
  377. */
  378.  
  379. /* COMNDi - interface to the COMND() library routine, giving a message if
  380.    a parse error occurs.  Returns TRUE or FALSE depending on success */
  381.  
  382. int COMNDi (CSBptr, CFBptr)
  383.  
  384. CSB        *CSBptr;        /* Address of command state block */
  385. CFB        *CFBptr;        /* Address of command function block */
  386.  
  387. {
  388. IND    int    i;            /* A counter */
  389. IND    char    *sptr;            /* A string pointer */
  390.  
  391. if (COMND(CSBptr, CFBptr) == _CROK)    /* If successful parse */
  392.     return (TRUE);            /*  then give good return */
  393. sptr = &CSBptr->CSB_BUF[CSBptr->CSB_PRS]; /* Get addr of unrecognized input */
  394. i = CSBptr->CSB_FLN - CSBptr->CSB_PRS;    /* Get # of chars unrecognized */
  395. printf (" ??Invalid- Can not recognize \"");
  396. while (i--)
  397.     putchar (*sptr++);            /* Print the bad string */
  398. printf ("\"... use ? here.\n");        /* Tell him how to proceed. */
  399. return (FALSE);                /* Give bad return */
  400. }
  401.