home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 1: Amiga / FrozenFish-Apr94.iso / bbs / alib / d5xx / d598 / parse.lha / Parse / src.lha / parse.c next >
C/C++ Source or Header  |  1992-01-30  |  16KB  |  523 lines

  1. #define UNIX 1
  2. /* #define NOISY 1 */      /* Use this if you want error messages from parse */
  3. /* #define DEMO 1 */
  4. /* #define VAX  1 */
  5. /* #define GENERAL 1 */  /* Use this to compile stuff which is also in
  6.                            General.c */
  7. /***************************************************************************
  8.  
  9.    Program:    
  10.    File:       Parse.c 
  11.    
  12.    Version:    V1.2FPU
  13.    Date:       11.07.90
  14.    Function:   A command parser.
  15.    
  16.    Copyright:  SciTech Software 1991
  17.    Author:     Andrew C. R. Martin
  18.    Address:    SciTech Software
  19.                23, Stag Leys,
  20.                Ashtead,
  21.                Surrey,
  22.                KT21 2TD.
  23.    Phone:      +44 (0372) 275775
  24.    EMail:      UUCP: cbmuk!cbmuka!scitec!amartin
  25.                JANET: andrew@uk.ac.ox.biop
  26.    Written while at:
  27.                Laboratory of Mathematical Biology
  28.                National Institue for Medical Research,
  29.                The Ridgeway,
  30.                Mill Hill,
  31.                London,
  32.                NW7 1AA
  33.                
  34. ****************************************************************************
  35.  
  36.    This program is not in the public domain, but it may be freely copied
  37.    and distributed for no charge providing this header is included.
  38.    The code may be modified as required, but any modifications must be
  39.    documented so that the person responsible can be identified. If someone
  40.    else breaks this code, I don't want to be blamed for code that does not
  41.    work! The code may not be sold commercially without prior permission from
  42.    the author, although it may be given away free with commercial products,
  43.    providing it is made clear that this program is free and that the source
  44.    code is provided with the program.
  45.  
  46. ****************************************************************************
  47.  
  48.    Description:
  49.    ============
  50.       parse() is a command line parser which will accept upper or
  51.       lower case commands and abbreviations. Comment lines may be
  52.       indicated using a !. The keyword structure aray and returned
  53.       string array are defined thus:
  54.               KeyWd keywords[NCOMM];
  55.               char  *strparam[MAXSTRPARAM];
  56.       The returned float parameters are defined thus:
  57.               float floatparam[MAXFLOATPARAM];
  58.       Space for the returned strings must be allocated thus:
  59.               strparam[n] = (char *)malloc(MAXSTRLEN * sizeof(char));
  60.       and repeated for each parameter.
  61.  
  62.       The keyword list with type and numbers of returned parameters
  63.       is constructed using the MAKEKEY macros:
  64.               MAKEKEY(keywords[0],"RANGE",NUMBER,2);
  65.               MAKEKEY(keywords[1],"STRING",STRING,1);
  66.       Here, the keywords must be defined in upper case.
  67.  
  68. ****************************************************************************
  69.  
  70.    Usage:
  71.    ======
  72. parse(comline,nkeys,keywords,floatparam,strparam)
  73. Input:      char  *comline       A command line string to parse
  74.             int   nkeys          Number of keywords
  75.             KeyWd *keywords      Array of keyword structures
  76. Output:     float *floatparam    Array of returned strings
  77.             char  **strparam     Array of pointers to returned strings
  78. Returns:    int                  Index of found command or error flag
  79. ****************************************************************************
  80.  
  81.    Revision History:
  82.    =================
  83.    V1.1   29.10.90
  84.    match() now frees the memory it allocates and calls terminate()
  85.    parse() now calls terminate() on the keyword string
  86.  
  87.    V1.2   25.09.91
  88.    Messages will only appear from parse() if NOISY is #defined.
  89.       
  90.  
  91. ***************************************************************************/
  92. #ifdef FPU
  93. #include <m68881.h>
  94. #endif
  95.  
  96. #include <stdio.h>
  97. #include <string.h>
  98. #include <math.h>
  99.  
  100. /* UNIX needs this to define toupper() */
  101. #ifdef UNIX
  102. #include <ctype.h>
  103. #endif
  104.  
  105. #include "mylib:parse.h"
  106.  
  107. /************************************************************************/
  108. /* General defines for these routines */
  109.  
  110. #define LF 10
  111. #define CR 13
  112. #define DIC 34   /* Double inverted commas */
  113.  
  114. /* The VAX confuses output to stdout and stderr when both are directed
  115.    to the same place (e.g. the screen), so it's easier to send everything
  116.    to stdout
  117. */
  118. #ifdef VAX
  119. #define OUTPUT stdout
  120. #else
  121. #define OUTPUT stderr
  122. #endif
  123.  
  124. #ifdef GENERAL
  125. /*************************************************************************
  126. KillLeadSpaces()
  127. Input:      char  *string        A character string
  128. Returns:   *char                 A pointer to the string with the leading
  129.                                  spaces removed
  130. This routine strips leading spaces from a string.
  131. *************************************************************************/
  132. char *KillLeadSpaces(string)
  133. char *string;
  134. {
  135.    while(*string == ' ') string++;
  136.    return(string);
  137. }
  138. #else
  139. extern char *KillLeadSpaces();
  140. #endif
  141.  
  142.  
  143.  
  144. /*************************************************************************
  145. parse()
  146. Input:      char  *comline       A command line string to parse
  147.             int   nkeys          Number of keywords
  148.             KeyWd *keywords      Array of keyword structures
  149. Output:     float *floatparam    Array of returned strings
  150.             char  **strparam     Array of pointers to returned strings
  151. Returns:    int                  Index of found command or error flag
  152. *************************************************************************/
  153. parse(comline,nkeys,keywords,floatparam,strparam)
  154. char  *comline,
  155.       **strparam;
  156. KeyWd *keywords;
  157. int   nkeys;
  158. float *floatparam;
  159. {
  160.    char *command;
  161.    int  i,n,found,nletters,nlett;
  162.  
  163.    command = KillLeadSpaces(comline);
  164.    terminate(command);
  165.    
  166.    found = 0;
  167.    if((command[0]=='!') ||
  168.       (command[0]==LF)  ||
  169.       (command[0]==CR)  ||
  170.       (command[0]=='\0'))
  171.       return(PARSE_COMMENT);
  172.  
  173.    for(i=0;i<nkeys;i++)
  174.    {
  175.       /* match() returns 1 if first string finishes first or exact match
  176.                          2 if second string finishes first
  177.                          0 if a mismatch
  178.          We only want to act in the first case
  179.       */
  180.       if((n=match(command,(keywords[i]).name,&nletters))==1)
  181.       {
  182. #ifdef DEBUG
  183.          printf("Matched letters: %d\n",nletters);
  184. #endif
  185.          if(found)  /* If found already */
  186.          {
  187. #ifdef NOISY
  188.             fprintf(OUTPUT,"Ambiguous keyword: %s\n",command);
  189. #endif
  190.             return(PARSE_ERRC);
  191.          }
  192.          found = i+1;  /* +1, so keyword 0 will flag TRUE */
  193.          nlett = nletters;
  194.       }
  195.    }
  196.    if(!found)
  197.    {
  198. #ifdef NOISY
  199.       fprintf(OUTPUT,"Keyword not known: %s\n",command);
  200. #endif
  201.       return(PARSE_ERRC);
  202.    }
  203.    command+=nlett;
  204.    found--; /* Reset to point to the correct keyword */
  205.  
  206. #ifdef DEBUG
  207.    printf("After getting command, line contains %s\n",command);
  208. #endif
  209.  
  210.    /* Get data requirements for this keyword */
  211.    if((keywords[found]).string)
  212.    {
  213. #ifdef DEBUG
  214.       printf("Command expects strings\n");
  215. #endif
  216.       for(i=0; i<(keywords[found]).nparam; i++)
  217.       {
  218.          command = KillLeadSpaces(command);
  219.          if((nletters = GetString(command,strparam[i]))==NULL)
  220.          {
  221. #ifdef NOISY
  222.             fprintf(OUTPUT,"Missing string parameter in: %s\n",comline);
  223.             fprintf(OUTPUT,"Command expects %d parameters\n",
  224.                    (keywords[found]).nparam);
  225. #endif
  226.             return(PARSE_ERRP);
  227.          }
  228.          command += nletters;
  229.       }  /* End of for(i) */
  230.    }
  231.    else
  232.    {
  233.       /* A numeric or no parameter */
  234. #ifdef DEBUG
  235.       printf("Command expects %d parameters\n",(keywords[found]).nparam);
  236. #endif
  237.       for(i=0; i<(keywords[found]).nparam; i++)
  238.       {
  239.          command = KillLeadSpaces(command);
  240.          if(!GetParam(command,&(floatparam[i]),&nletters))
  241.          {
  242. #ifdef NOISY
  243.             fprintf(OUTPUT,"Error in parameter %s\n",comline);
  244.             fprintf(OUTPUT,"Command expects %d numeric parameters\n",
  245.                    (keywords[found]).nparam);
  246. #endif
  247.             return(PARSE_ERRP);
  248.          }
  249.          command += nletters;
  250.       }  /* End of for(i) */
  251.    }  /* End of else */
  252.    return(found);
  253. }
  254.  
  255.  
  256.  
  257.  
  258. /*************************************************************************
  259. match()
  260. Input:      char  *comstring     A character string
  261.             char  *string2       A second string
  262. Output:     int   *nletters      Number of letters matched
  263. Returns:    int                  0 String mismatch
  264.                                  1 First string finished first
  265.                                  2 Second string finished first
  266.  
  267. This routine matches two strings, but stops the comparison as soon
  268. as a space or NULL is found in either string. Th returned value
  269. indicates which string finished first or 0 if the letters before the
  270. space or NULL have a mismatch. The routine calls String ToUpper()
  271. on `comstring' before the comparison.
  272. *************************************************************************/
  273. match(comstring,string2,nletters)
  274. char *comstring,*string2;
  275. int  *nletters;
  276. {
  277.    int  i;
  278.    char *string1;
  279.  
  280.    terminate(comstring);
  281.    terminate(string2);
  282.    string1 = (char *)malloc((strlen(comstring) + 2) * sizeof(char));
  283.    StringToUpper(comstring,string1);
  284.  
  285. #ifdef DEBUG
  286.    printf("After U/C:  %s\n",string1);
  287.    printf("Keyword:    %s\n\n",string2);
  288. #endif
  289.  
  290.    for(i=0;;i++)
  291.    {
  292.       if((!string1[i])||(string1[i]==' '))
  293.       {
  294.          *nletters = i;
  295.          return(1);
  296.       }
  297.       if((!string2[i])||(string2[i]==' '))
  298.       {
  299.          *nletters = i;
  300.          return(2);
  301.       }
  302.       if(string1[i] != string2[i])
  303.       {
  304.          *nletters = i;
  305.          return(0);
  306.       }
  307.    }
  308.    free(string1);
  309. }
  310.  
  311.  
  312.  
  313.  
  314. /*************************************************************************
  315. GetString()
  316. Input:      char  *command       A character string
  317. Output:     char  *strparam      Returned character string
  318. Returns:    int                  Number of characters pulled out
  319.                                  of the command string
  320.  
  321. This routine returns the first space-delimited group of characters
  322. from character string `command'
  323. *************************************************************************/
  324. GetString(command,strparam)
  325. char *command,*strparam;
  326. {
  327.    int i,j,inv_commas;
  328.  
  329.    inv_commas=0;
  330.    j=0;
  331.    for(i=0;;i++)
  332.    {
  333.       if(command[i]==DIC)
  334.       {
  335.          /* Toggle the inv_commas flag */
  336.          inv_commas = abs(inv_commas-1);
  337.          /* Don't copy anything */
  338.          continue;
  339.       }
  340.  
  341.       /* Break out if we're at the end of a line */
  342.       if((command[i]==LF)
  343.        ||(command[i]==CR)
  344.        ||(command[i]=='\0')) break;
  345.  
  346.       /* Also break out if we've a space and we're not between
  347.          inverted commas */
  348.       if((command[i]==' ') && (!inv_commas)) break;
  349.  
  350.       /* Other wise copy the character */
  351.       strparam[j++] = command[i];
  352.    }
  353.    strparam[j]='\0';
  354.    return(i);
  355. }
  356.  
  357.  
  358.  
  359. /*************************************************************************
  360. GetParam()
  361. Input:      char  *command       A character string
  362. Output:     float *value         Returned float value
  363.             int   *nletters      Number of charcters pulled out
  364.                                  of the command string
  365. Returns:    int                  0 If error
  366.                                  1 If OK
  367.  
  368. This routine extracts the first space-delimited number from the
  369. `command' character string.
  370. *************************************************************************/
  371. GetParam(command,value,nletters)
  372. char  *command;
  373. float *value;
  374. int   *nletters;
  375. {
  376.    char buffer[50];
  377.    int  retval;
  378.  
  379.    if((*nletters = GetString(command,buffer))==NULL)
  380.       return(0);
  381.  
  382.    retval = sscanf(buffer,"%f",value);
  383.    return(retval);
  384. }
  385.  
  386.  
  387.  
  388. #ifdef GENERAL
  389. /*************************************************************************
  390. StringToUpper()
  391. Input:      char  *string1       A character string
  392. Output:     char  *string2       A second string
  393.  
  394. This routine converts a lower or mixed case string to upper case
  395. *************************************************************************/
  396. StringToUpper(string1,string2)
  397. char *string1,*string2;
  398. {
  399.    int i;
  400.  
  401.    for(i=0;i<strlen(string1);i++)
  402.       string2[i] = toupper(string1[i]);
  403.  
  404.    string2[i] = '\0';
  405.  
  406.    return(0);
  407. }
  408. #endif
  409.  
  410. /*************************************************************************
  411. terminate(string)
  412. Input/Output:   char  *string       A character string
  413.  
  414. This routine terminates a string at the first \n
  415. *************************************************************************/
  416. terminate(string)
  417. char *string;
  418. {
  419.    int i=0;
  420.    
  421.    for(i=0;string[i];i++)
  422.    {
  423.       if(string[i] == '\n')
  424.       {
  425.          string[i] = '\0';
  426.          break;
  427.       }
  428.    }
  429.    return(0);
  430. }
  431.  
  432.  
  433. /*************************************************************************/
  434. /*                                                                       */
  435. /*                             DEMO CODE                                 */
  436. /*                                                                       */
  437. /*************************************************************************/
  438.  
  439. #ifdef DEMO
  440.  
  441. #define NCOMM 9                  /* Number of keywords                   */
  442. #define MAXNUMPARAM 10           /* Max number of numeric parameters     */
  443. #define MAXSTRPARAM 2            /* Max number of string parameters      */
  444. #define MAXSTRLEN   80           /* Max length of retuyrned string       */
  445. main()
  446. {
  447.    KeyWd keywords[NCOMM];        /* Array to store keywords              */
  448.    char  *strparam[MAXSTRPARAM], /* Array for returned strings           */
  449.          comline[100];           /* The command line for parsing         */
  450.    int   key;                    /* Return value from parse()            */
  451.    float numparam[MAXNUMPARAM];  /* Array for returned numbers           */
  452.    int   i;                      /* Counter                              */
  453.  
  454.    /* Initialise returned string array */
  455.    for(i=0; i<MAXSTRPARAM; i++)
  456.       strparam[i] = (char *)malloc(MAXSTRLEN * sizeof(char));
  457.  
  458.    /* Construct the keywords */
  459.    MAKEKEY(keywords[0],"END",       NUMBER,0);
  460.    MAKEKEY(keywords[1],"STRING",    STRING,1);
  461.    MAKEKEY(keywords[2],"FLOAT",     NUMBER,1);
  462.    MAKEKEY(keywords[3],"INT",       NUMBER,1);
  463.    MAKEKEY(keywords[4],"NOTHING",   NUMBER,0);
  464.    MAKEKEY(keywords[5],"NULL",      NUMBER,0);
  465.    MAKEKEY(keywords[6],"TWOSTRINGS",STRING,2);
  466.    MAKEKEY(keywords[7],"RANGE",     NUMBER,2);
  467.    MAKEKEY(keywords[8],"HELP",      NUMBER,0);
  468.  
  469.    /* Print a message */
  470.    printf("Known Commands:\nRANGE, STRING, FLOAT, INT, NOTHING, NULL, \
  471. TWOSTRINGS, END, HELP\n");
  472.  
  473.    /* Start a loop in which we read a string from the keyboard
  474.       and parse it. The keyword list is designed so END returns 0
  475.    */
  476.    key = 1;
  477.    while(key)
  478.    {
  479.       printf("Test> ");
  480.       gets(comline);
  481.       key = parse(comline,NCOMM,keywords,numparam,strparam);
  482.  
  483.       /* Carry out appropriate action for each keyword. This
  484.          could be made more readable by #define'ing a label for
  485.          each key number which matches the command name */
  486.       switch(key)
  487.       {
  488.       case PARSE_ERRC:
  489.       case PARSE_ERRP:
  490.       case PARSE_COMMENT:
  491.          break;
  492.       case 0:
  493.          printf("END: Goodbye!\n");
  494.          break;
  495.       case 1:
  496.          printf("STRING: %s\n",strparam[0]);
  497.          break;
  498.       case 2:
  499.          printf("FLOAT: Value %f\n",numparam[0]);
  500.          break;
  501.       case 3:
  502.          printf("INT:   Value %f\n",numparam[0]);
  503.          break;
  504.       case 4:
  505.          printf("NOTHING\n");
  506.          break;
  507.       case 5:
  508.          printf("NULL\n");
  509.          break;
  510.       case 6:
  511.          printf("TWOSTRINGS:\n%s\n%s\n",strparam[0],strparam[1]);
  512.          break;
  513.       case 7:
  514.          printf("RANGE: Values %f,%f\n",numparam[0],numparam[1]);
  515.          break;
  516.       case 8:
  517.          printf("Known Commands:\nRANGE, STRING, FLOAT, INT, NOTHING, NULL, \
  518. TWOSTRINGS, END, HELP\n");
  519.       }
  520.    }
  521. }
  522. #endif
  523.