home *** CD-ROM | disk | FTP | other *** search
/ ftp.barnyard.co.uk / 2015.02.ftp.barnyard.co.uk.tar / ftp.barnyard.co.uk / cpm / walnut-creek-CDROM / CPM / AZTEC-C / COMND004.ARK / TEST.C < prev   
C/C++ Source or Header  |  1986-06-17  |  12KB  |  400 lines

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