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 >
Wrap
C/C++ Source or Header
|
1992-01-30
|
16KB
|
523 lines
#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