home *** CD-ROM | disk | FTP | other *** search
- #define UNIX 1
- /* #define NOISY 1 */ /* Use this if you want error messages from parse */
- /* #define DEMO 1 */
- /* #define VAX 1 */
- /* #define GENERAL 1 */ /* Use this to compile stuff which is also in
- General.c */
- /***************************************************************************
-
- Program:
- File: Parse.c
-
- Version: V1.2FPU
- Date: 11.07.90
- Function: A command parser.
-
- Copyright: SciTech Software 1991
- Author: Andrew C. R. Martin
- Address: SciTech Software
- 23, Stag Leys,
- Ashtead,
- Surrey,
- KT21 2TD.
- Phone: +44 (0372) 275775
- EMail: UUCP: cbmuk!cbmuka!scitec!amartin
- JANET: andrew@uk.ac.ox.biop
- Written while at:
- Laboratory of Mathematical Biology
- National Institue for Medical Research,
- The Ridgeway,
- Mill Hill,
- London,
- NW7 1AA
-
- ****************************************************************************
-
- This program is not in the public domain, but it may be freely copied
- and distributed for no charge providing this header is included.
- The code may be modified as required, but any modifications must be
- documented so that the person responsible can be identified. If someone
- else breaks this code, I don't want to be blamed for code that does not
- work! The code may not be sold commercially without prior permission from
- the author, although it may be given away free with commercial products,
- providing it is made clear that this program is free and that the source
- code is provided with the program.
-
- ****************************************************************************
-
- Description:
- ============
- parse() is a command line parser which will accept upper or
- lower case commands and abbreviations. Comment lines may be
- indicated using a !. The keyword structure aray and returned
- string array are defined thus:
- KeyWd keywords[NCOMM];
- char *strparam[MAXSTRPARAM];
- The returned float parameters are defined thus:
- float floatparam[MAXFLOATPARAM];
- Space for the returned strings must be allocated thus:
- strparam[n] = (char *)malloc(MAXSTRLEN * sizeof(char));
- and repeated for each parameter.
-
- The keyword list with type and numbers of returned parameters
- is constructed using the MAKEKEY macros:
- MAKEKEY(keywords[0],"RANGE",NUMBER,2);
- MAKEKEY(keywords[1],"STRING",STRING,1);
- Here, the keywords must be defined in upper case.
-
- ****************************************************************************
-
- Usage:
- ======
- parse(comline,nkeys,keywords,floatparam,strparam)
- Input: char *comline A command line string to parse
- int nkeys Number of keywords
- KeyWd *keywords Array of keyword structures
- Output: float *floatparam Array of returned strings
- char **strparam Array of pointers to returned strings
- Returns: int Index of found command or error flag
- ****************************************************************************
-
- Revision History:
- =================
- V1.1 29.10.90
- match() now frees the memory it allocates and calls terminate()
- parse() now calls terminate() on the keyword string
-
- V1.2 25.09.91
- Messages will only appear from parse() if NOISY is #defined.
-
-
- ***************************************************************************/
- #ifdef FPU
- #include <m68881.h>
- #endif
-
- #include <stdio.h>
- #include <string.h>
- #include <math.h>
-
- /* UNIX needs this to define toupper() */
- #ifdef UNIX
- #include <ctype.h>
- #endif
-
- #include "mylib:parse.h"
-
- /************************************************************************/
- /* General defines for these routines */
-
- #define LF 10
- #define CR 13
- #define DIC 34 /* Double inverted commas */
-
- /* The VAX confuses output to stdout and stderr when both are directed
- to the same place (e.g. the screen), so it's easier to send everything
- to stdout
- */
- #ifdef VAX
- #define OUTPUT stdout
- #else
- #define OUTPUT stderr
- #endif
-
- #ifdef GENERAL
- /*************************************************************************
- KillLeadSpaces()
- Input: char *string A character string
- Returns: *char A pointer to the string with the leading
- spaces removed
- This routine strips leading spaces from a string.
- *************************************************************************/
- char *KillLeadSpaces(string)
- char *string;
- {
- while(*string == ' ') string++;
- return(string);
- }
- #else
- extern char *KillLeadSpaces();
- #endif
-
-
-
- /*************************************************************************
- parse()
- Input: char *comline A command line string to parse
- int nkeys Number of keywords
- KeyWd *keywords Array of keyword structures
- Output: float *floatparam Array of returned strings
- char **strparam Array of pointers to returned strings
- Returns: int Index of found command or error flag
- *************************************************************************/
- parse(comline,nkeys,keywords,floatparam,strparam)
- char *comline,
- **strparam;
- KeyWd *keywords;
- int nkeys;
- float *floatparam;
- {
- char *command;
- int i,n,found,nletters,nlett;
-
- command = KillLeadSpaces(comline);
- terminate(command);
-
- found = 0;
- if((command[0]=='!') ||
- (command[0]==LF) ||
- (command[0]==CR) ||
- (command[0]=='\0'))
- return(PARSE_COMMENT);
-
- for(i=0;i<nkeys;i++)
- {
- /* match() returns 1 if first string finishes first or exact match
- 2 if second string finishes first
- 0 if a mismatch
- We only want to act in the first case
- */
- if((n=match(command,(keywords[i]).name,&nletters))==1)
- {
- #ifdef DEBUG
- printf("Matched letters: %d\n",nletters);
- #endif
- if(found) /* If found already */
- {
- #ifdef NOISY
- fprintf(OUTPUT,"Ambiguous keyword: %s\n",command);
- #endif
- return(PARSE_ERRC);
- }
- found = i+1; /* +1, so keyword 0 will flag TRUE */
- nlett = nletters;
- }
- }
- if(!found)
- {
- #ifdef NOISY
- fprintf(OUTPUT,"Keyword not known: %s\n",command);
- #endif
- return(PARSE_ERRC);
- }
- command+=nlett;
- found--; /* Reset to point to the correct keyword */
-
- #ifdef DEBUG
- printf("After getting command, line contains %s\n",command);
- #endif
-
- /* Get data requirements for this keyword */
- if((keywords[found]).string)
- {
- #ifdef DEBUG
- printf("Command expects strings\n");
- #endif
- for(i=0; i<(keywords[found]).nparam; i++)
- {
- command = KillLeadSpaces(command);
- if((nletters = GetString(command,strparam[i]))==NULL)
- {
- #ifdef NOISY
- fprintf(OUTPUT,"Missing string parameter in: %s\n",comline);
- fprintf(OUTPUT,"Command expects %d parameters\n",
- (keywords[found]).nparam);
- #endif
- return(PARSE_ERRP);
- }
- command += nletters;
- } /* End of for(i) */
- }
- else
- {
- /* A numeric or no parameter */
- #ifdef DEBUG
- printf("Command expects %d parameters\n",(keywords[found]).nparam);
- #endif
- for(i=0; i<(keywords[found]).nparam; i++)
- {
- command = KillLeadSpaces(command);
- if(!GetParam(command,&(floatparam[i]),&nletters))
- {
- #ifdef NOISY
- fprintf(OUTPUT,"Error in parameter %s\n",comline);
- fprintf(OUTPUT,"Command expects %d numeric parameters\n",
- (keywords[found]).nparam);
- #endif
- return(PARSE_ERRP);
- }
- command += nletters;
- } /* End of for(i) */
- } /* End of else */
- return(found);
- }
-
-
-
-
- /*************************************************************************
- match()
- Input: char *comstring A character string
- char *string2 A second string
- Output: int *nletters Number of letters matched
- Returns: int 0 String mismatch
- 1 First string finished first
- 2 Second string finished first
-
- This routine matches two strings, but stops the comparison as soon
- as a space or NULL is found in either string. Th returned value
- indicates which string finished first or 0 if the letters before the
- space or NULL have a mismatch. The routine calls String ToUpper()
- on `comstring' before the comparison.
- *************************************************************************/
- match(comstring,string2,nletters)
- char *comstring,*string2;
- int *nletters;
- {
- int i;
- char *string1;
-
- terminate(comstring);
- terminate(string2);
- string1 = (char *)malloc((strlen(comstring) + 2) * sizeof(char));
- StringToUpper(comstring,string1);
-
- #ifdef DEBUG
- printf("After U/C: %s\n",string1);
- printf("Keyword: %s\n\n",string2);
- #endif
-
- for(i=0;;i++)
- {
- if((!string1[i])||(string1[i]==' '))
- {
- *nletters = i;
- return(1);
- }
- if((!string2[i])||(string2[i]==' '))
- {
- *nletters = i;
- return(2);
- }
- if(string1[i] != string2[i])
- {
- *nletters = i;
- return(0);
- }
- }
- free(string1);
- }
-
-
-
-
- /*************************************************************************
- GetString()
- Input: char *command A character string
- Output: char *strparam Returned character string
- Returns: int Number of characters pulled out
- of the command string
-
- This routine returns the first space-delimited group of characters
- from character string `command'
- *************************************************************************/
- GetString(command,strparam)
- char *command,*strparam;
- {
- int i,j,inv_commas;
-
- inv_commas=0;
- j=0;
- for(i=0;;i++)
- {
- if(command[i]==DIC)
- {
- /* Toggle the inv_commas flag */
- inv_commas = abs(inv_commas-1);
- /* Don't copy anything */
- continue;
- }
-
- /* Break out if we're at the end of a line */
- if((command[i]==LF)
- ||(command[i]==CR)
- ||(command[i]=='\0')) break;
-
- /* Also break out if we've a space and we're not between
- inverted commas */
- if((command[i]==' ') && (!inv_commas)) break;
-
- /* Other wise copy the character */
- strparam[j++] = command[i];
- }
- strparam[j]='\0';
- return(i);
- }
-
-
-
- /*************************************************************************
- GetParam()
- Input: char *command A character string
- Output: float *value Returned float value
- int *nletters Number of charcters pulled out
- of the command string
- Returns: int 0 If error
- 1 If OK
-
- This routine extracts the first space-delimited number from the
- `command' character string.
- *************************************************************************/
- GetParam(command,value,nletters)
- char *command;
- float *value;
- int *nletters;
- {
- char buffer[50];
- int retval;
-
- if((*nletters = GetString(command,buffer))==NULL)
- return(0);
-
- retval = sscanf(buffer,"%f",value);
- return(retval);
- }
-
-
-
- #ifdef GENERAL
- /*************************************************************************
- StringToUpper()
- Input: char *string1 A character string
- Output: char *string2 A second string
-
- This routine converts a lower or mixed case string to upper case
- *************************************************************************/
- StringToUpper(string1,string2)
- char *string1,*string2;
- {
- int i;
-
- for(i=0;i<strlen(string1);i++)
- string2[i] = toupper(string1[i]);
-
- string2[i] = '\0';
-
- return(0);
- }
- #endif
-
- /*************************************************************************
- terminate(string)
- Input/Output: char *string A character string
-
- This routine terminates a string at the first \n
- *************************************************************************/
- terminate(string)
- char *string;
- {
- int i=0;
-
- for(i=0;string[i];i++)
- {
- if(string[i] == '\n')
- {
- string[i] = '\0';
- break;
- }
- }
- return(0);
- }
-
-
- /*************************************************************************/
- /* */
- /* DEMO CODE */
- /* */
- /*************************************************************************/
-
- #ifdef DEMO
-
- #define NCOMM 9 /* Number of keywords */
- #define MAXNUMPARAM 10 /* Max number of numeric parameters */
- #define MAXSTRPARAM 2 /* Max number of string parameters */
- #define MAXSTRLEN 80 /* Max length of retuyrned string */
- main()
- {
- KeyWd keywords[NCOMM]; /* Array to store keywords */
- char *strparam[MAXSTRPARAM], /* Array for returned strings */
- comline[100]; /* The command line for parsing */
- int key; /* Return value from parse() */
- float numparam[MAXNUMPARAM]; /* Array for returned numbers */
- int i; /* Counter */
-
- /* Initialise returned string array */
- for(i=0; i<MAXSTRPARAM; i++)
- strparam[i] = (char *)malloc(MAXSTRLEN * sizeof(char));
-
- /* Construct the keywords */
- MAKEKEY(keywords[0],"END", NUMBER,0);
- MAKEKEY(keywords[1],"STRING", STRING,1);
- MAKEKEY(keywords[2],"FLOAT", NUMBER,1);
- MAKEKEY(keywords[3],"INT", NUMBER,1);
- MAKEKEY(keywords[4],"NOTHING", NUMBER,0);
- MAKEKEY(keywords[5],"NULL", NUMBER,0);
- MAKEKEY(keywords[6],"TWOSTRINGS",STRING,2);
- MAKEKEY(keywords[7],"RANGE", NUMBER,2);
- MAKEKEY(keywords[8],"HELP", NUMBER,0);
-
- /* Print a message */
- printf("Known Commands:\nRANGE, STRING, FLOAT, INT, NOTHING, NULL, \
- TWOSTRINGS, END, HELP\n");
-
- /* Start a loop in which we read a string from the keyboard
- and parse it. The keyword list is designed so END returns 0
- */
- key = 1;
- while(key)
- {
- printf("Test> ");
- gets(comline);
- key = parse(comline,NCOMM,keywords,numparam,strparam);
-
- /* Carry out appropriate action for each keyword. This
- could be made more readable by #define'ing a label for
- each key number which matches the command name */
- switch(key)
- {
- case PARSE_ERRC:
- case PARSE_ERRP:
- case PARSE_COMMENT:
- break;
- case 0:
- printf("END: Goodbye!\n");
- break;
- case 1:
- printf("STRING: %s\n",strparam[0]);
- break;
- case 2:
- printf("FLOAT: Value %f\n",numparam[0]);
- break;
- case 3:
- printf("INT: Value %f\n",numparam[0]);
- break;
- case 4:
- printf("NOTHING\n");
- break;
- case 5:
- printf("NULL\n");
- break;
- case 6:
- printf("TWOSTRINGS:\n%s\n%s\n",strparam[0],strparam[1]);
- break;
- case 7:
- printf("RANGE: Values %f,%f\n",numparam[0],numparam[1]);
- break;
- case 8:
- printf("Known Commands:\nRANGE, STRING, FLOAT, INT, NOTHING, NULL, \
- TWOSTRINGS, END, HELP\n");
- }
- }
- }
- #endif
-