Bioplib
Protein Structure C Library
 All Data Structures Files Functions Variables Typedefs Macros Pages
parse.c
Go to the documentation of this file.
1 /************************************************************************/
2 /**
3 
4  \file parse.c
5 
6  \version V1.11
7  \date 07.07.14
8  \brief A keyword command parser
9 
10  \copyright (c) UCL / Dr. Andrew C. R. Martin 1990-2014
11  \author Dr. Andrew C. R. Martin
12  \par
13  Institute of Structural & Molecular Biology,
14  University College London,
15  Gower Street,
16  London.
17  WC1E 6BT.
18  \par
19  andrew@bioinf.org.uk
20  andrew.martin@ucl.ac.uk
21 
22 **************************************************************************
23 
24  This code is NOT IN THE PUBLIC DOMAIN, but it may be copied
25  according to the conditions laid out in the accompanying file
26  COPYING.DOC.
27 
28  The code may be modified as required, but any modifications must be
29  documented so that the person responsible can be identified.
30 
31  The code may not be sold commercially or included as part of a
32  commercial product except as described in the file COPYING.DOC.
33 
34 **************************************************************************
35 
36  Description:
37  ============
38 
39  blParse() is a command line parser which will accept upper or
40  lower case commands and abbreviations. Comment lines may be
41  indicated using a !. The keyword structure array and returned
42  string array are defined thus:
43 \code
44  KeyWd keywords[NCOMM];
45  char *strparam[MAXSTRPARAM];
46 \endcode
47 
48  The returned REAL parameters are defined thus:
49 \code
50  REAL floatparam[MAXFLOATPARAM];
51 \endcode
52 
53  Space for the returned strings must be allocated thus:
54 \code
55  strparam[n] = (char *)malloc(MAXSTRLEN * sizeof(char));
56 \endcode
57  and repeated for each parameter.
58 
59  The keyword list with type and numbers of returned parameters
60  is constructed using the MAKEKEY macros:
61 \code
62  MAKEKEY(keywords[0],"RANGE",NUMBER,2);
63  MAKEKEY(keywords[1],"STRING",STRING,1);
64 \endcode
65  Here, the keywords must be defined in upper case.
66 
67 
68  blMparse() is used in the same way, but allows a variable number of
69  parameters for each keyword. Keywords are of type MKeyWd and are
70  defined using the macro MAKEMKEY:
71 \code
72  MAKEMKEY(keywords[0],"RANGE",NUMBER,2,2);
73  MAKEMKEY(keywords[1],"STRING",STRING,1,3);
74 \endcode
75 
76 **************************************************************************
77 
78  Usage:
79  ======
80 
81 \code
82  blParse(comline,nkeys,keywords,floatparam,strparam)
83 \endcode
84 
85  \param[in] *comline A command line string to parse
86  \param[in] nkeys Number of keywords
87  \param[in] *keywords Array of keyword structures
88  \param[out] *floatparam Array of returned strings
89  \param[out] **strparam Array of pointers to returned strings
90  \return Index of found command or error flag
91 
92 \code
93  blMparse(comline,nkeys,keywords,floatparam,strparam,nparam)
94 \endcode
95 
96  \param[in] *comline A command line string to parse
97  \param[in] nkeys Number of keywords
98  \param[in] *keywords Array of keyword structures
99  \param[out] *floatparam Array of returned strings
100  \param[out] **strparam Array of pointers to returned strings
101  \param[out] *nparam Number of parameters found
102  \return Index of found command or error flag
103 
104 
105 **************************************************************************
106 
107  Revision History:
108  =================
109 - V1.0 11.07.90 Original
110 - V1.1 29.10.90 match() now frees the memory it allocates and calls
111  terminate()
112  parse() now calls terminate() on the keyword string
113 - V1.2 25.09.91 Messages will only appear from parse() if NOISY is
114  #defined.
115  Added FPU support.
116 - V1.3 28.05.92 ANSIed and autodoc'd
117 - V1.4 08.12.92 Includes stdlib.h
118 - V1.5 22.04.93 Various tidying to exact ANSI standard and of function
119  headers. Corrected some calls to free()
120 - V1.6 16.06.93 Tidied for book
121 - V1.7 01.03.94 Added mparse()
122 - V1.8 11.03.94 Added internal support for lines starting with a $.
123  The line is passed as a system() call and parse()
124  acts as if the line had been a comment.
125 - V1.9 08.10.99 Initialised some variables
126 - V1.10 28.02.11 Added # as a comment introducer
127 - V1.11 07.07.14 Use bl prefix for functions By: CTP
128 
129 *************************************************************************/
130 /* Doxygen
131  -------
132  #GROUP General Programming
133  #SUBGROUP User interaction
134  #FUNCTION blParse()
135  Keyword-based command parser using a fixed number of parameters per
136  command
137 
138  #FUNCTION blMparse()
139  As blParse(), but allows variable number of parameters to each keyword.
140 
141 
142 
143  #SUBGROUP String handling
144 
145  #FUNCTION blMatch()
146  Matches two strings, but stops the comparison as soon
147  as a space or NULL is found in either string. The returned value
148 
149  #FUNCTION blGetString()
150  Returns the first space-delimited group of characters
151  from a character string
152 
153  #FUNCTION blGetParam()
154  Extracts the first space-delimited number from a
155  character string.
156 */
157 /************************************************************************/
158 /* Includes
159 */
160 #include <stdio.h>
161 #include <string.h>
162 #include <math.h>
163 #include <stdlib.h>
164 #include <ctype.h>
165 
166 #include "MathType.h"
167 #include "SysDefs.h"
168 #include "macros.h"
169 #include "parse.h"
170 #include "general.h"
171 
172 /************************************************************************/
173 /* General defines for these routines
174 */
175 #define LF 10
176 #define CR 13
177 #define DIC 34 /* Double inverted commas */
178 
179 /************************************************************************/
180 /*>int blParse(char *comline, int nkeys, KeyWd *keywords,
181  REAL *floatparam, char **strparam)
182  ----------------------------------------------------
183 *//**
184 
185  \param[in] *comline A command line string to parse
186  \param[in] nkeys Number of keywords
187  \param[in] *keywords Array of keyword structures
188  \param[out] *floatparam Array of returned strings
189  \param[out] **strparam Array of pointers to returned strings
190  \return Index of found command or error flag
191 
192  Keyword-based command parser using a fixed number of parameters per
193  command
194 
195 - 11.07.90 Original By: ACRM
196 - 22.04.93 Tidied comments, etc. Corrected NULL to 0.
197 - 11.03.94 Added $ line handling
198 - 08.10.99 Initialise nlett
199 - 28.02.11 Added # for comments
200 - 07.07.14 Use bl prefix for functions By: CTP
201 */
202 int blParse(char *comline,
203  int nkeys,
204  KeyWd *keywords,
205  REAL *floatparam,
206  char **strparam)
207 {
208  char *command;
209  int i,n,found,nletters,nlett = 0;
210 
211  command = blKillLeadSpaces(comline);
212  TERMINATE(command);
213 
214  if(command[0] == '$')
215  {
216  system(command+1);
217  return(PARSE_COMMENT);
218  }
219 
220  found = 0;
221  if((command[0]=='!') ||
222  (command[0]=='#') ||
223  (command[0]==LF) ||
224  (command[0]==CR) ||
225  (command[0]=='\0'))
226  return(PARSE_COMMENT);
227 
228  for(i=0;i<nkeys;i++)
229  {
230  /* match() returns 1 if first string finishes first or exact match
231  2 if second string finishes first
232  0 if a mismatch
233  We only want to act in the first case
234  */
235  if((n=blMatch(command,(keywords[i]).name,&nletters))==1)
236  {
237  if(found) /* If found already */
238  {
239  return(PARSE_ERRC);
240  }
241  found = i+1; /* +1, so keyword 0 will flag TRUE */
242  nlett = nletters;
243  }
244  }
245  if(!found)
246  {
247  return(PARSE_ERRC);
248  }
249  command+=nlett;
250  found--; /* Reset to point to the correct keyword */
251 
252  /* Get data requirements for this keyword */
253  if((keywords[found]).string)
254  {
255  for(i=0; i<(keywords[found]).nparam; i++)
256  {
257  command = blKillLeadSpaces(command);
258  if((nletters = blGetString(command,strparam[i]))==0)
259  {
260  return(PARSE_ERRP);
261  }
262  command += nletters;
263  } /* End of for(i) */
264  }
265  else
266  {
267  /* A numeric or no parameter */
268  for(i=0; i<(keywords[found]).nparam; i++)
269  {
270  command = blKillLeadSpaces(command);
271  if(!blGetParam(command,&(floatparam[i]),&nletters))
272  {
273  return(PARSE_ERRP);
274  }
275  command += nletters;
276  } /* End of for(i) */
277  } /* End of else */
278  return(found);
279 }
280 
281 /************************************************************************/
282 /*>int blMatch(char *comstring, char *string2, int *nletters)
283  ----------------------------------------------------------
284 *//**
285 
286  \param[in] *comstring A character string
287  \param[in] *string2 A second string
288  \param[out] *nletters Number of letters matched
289  \return 0 String mismatch
290  1 First string finished first
291  2 Second string finished first
292 
293  Matches two strings, but stops the comparison as soon
294  as a space or NULL is found in either string. The returned value
295  indicates which string finished first or 0 if the letters before the
296  space or NULL have a mismatch. The routine calls StringToUpper()
297  on `comstring' before the comparison.
298 
299 - 11.07.90 Original By: ACRM
300 - 22.04.93 Tidied comments, etc. Added check on malloc and corrected
301  calls to free()
302 - 07.07.14 Use bl prefix for functions By: CTP
303 */
304 int blMatch(char *comstring,
305  char *string2,
306  int *nletters)
307 {
308  int i;
309  char *string1;
310 
311  TERMINATE(comstring);
312  TERMINATE(string2);
313  string1 = (char *)malloc((strlen(comstring) + 2) * sizeof(char));
314  if(string1 == NULL) return(0);
315 
316  blStringToUpper(comstring,string1);
317 
318  for(i=0;;i++)
319  {
320  if((!string1[i])||(string1[i]==' '))
321  {
322  *nletters = i;
323  free(string1);
324  return(1);
325  }
326  if((!string2[i])||(string2[i]==' '))
327  {
328  *nletters = i;
329  free(string1);
330  return(2);
331  }
332  if(string1[i] != string2[i])
333  {
334  *nletters = i;
335  free(string1);
336  return(0);
337  }
338  }
339 }
340 
341 /************************************************************************/
342 /*>int blGetString(char *command, char *strparam)
343  ----------------------------------------------
344 *//**
345 
346  \param[in] *command A character string
347  \param[out] *strparam Returned character string
348  \return Number of characters pulled out
349  of the command string
350 
351  Returns the first space-delimited group of characters
352  from character string `command'
353 
354 - 11.07.90 Original By: ACRM
355 - 22.04.93 Tidied comments, etc. Changed toggle method
356 - 07.07.14 Use bl prefix for functions By: CTP
357 */
358 int blGetString(char *command,
359  char *strparam)
360 {
361  int i,j,inv_commas;
362 
363  inv_commas=0;
364  j=0;
365  for(i=0;;i++)
366  {
367  if(command[i]==DIC)
368  {
369  /* Toggle the inv_commas flag */
370  inv_commas = !inv_commas;
371 
372  /* Don't copy anything */
373  continue;
374  }
375 
376  /* Break out if we're at the end of a line */
377  if((command[i]==LF)
378  ||(command[i]==CR)
379  ||(command[i]=='\0')) break;
380 
381  /* Also break out if we've a space and we're not between
382  inverted commas
383  */
384  if((command[i]==' ') && (!inv_commas)) break;
385 
386  /* Other wise copy the character */
387  strparam[j++] = command[i];
388  }
389  strparam[j]='\0';
390  return(i);
391 }
392 
393 /************************************************************************/
394 /*>int blGetParam(char *command, REAL *value, int *nletters)
395  ---------------------------------------------------------
396 *//**
397 
398  \param[in] *command A character string
399  \param[out] *value Returned float value
400  \param[out] *nletters Number of charcters pulled out
401  of the command string
402  \return 0 If error
403  1 If OK
404 
405  Extracts the first space-delimited number from the
406  `command' character string.
407 
408 - 11.07.90 Original By: ACRM
409 - 22.04.93 Tidied comments, etc. Corrected NULL to 0
410 - 07.07.14 Use bl prefix for functions By: CTP
411 */
412 int blGetParam(char *command,
413  REAL *value,
414  int *nletters)
415 {
416  char buffer[50];
417  int retval;
418 
419  if((*nletters = blGetString(command,buffer))==0)
420  return(0);
421 
422  retval = sscanf(buffer,"%lf",value);
423  return(retval);
424 }
425 
426 /************************************************************************/
427 /*>int blMparse(char *comline, int nkeys, MKeyWd *keywords,
428  REAL *floatparam, char **strparam, int *nparam)
429  ------------------------------------------------------------
430 *//**
431 
432  \param[in] *comline A command line string to parse
433  \param[in] nkeys Number of keywords
434  \param[in] *keywords Array of keyword structures
435  \param[out] *floatparam Array of returned strings
436  \param[out] **strparam Array of pointers to returned strings
437  \param[out] *nparam Number of parameters found
438  \return Index of found command or error flag
439 
440  As blParse(), but allows variable number of parameters to each keyword.
441 
442 - 23.02.94 Original based on parse() By: ACRM
443 - 11.03.94 Added $ line handling
444 - 08.10.99 Initialise nlett to 0
445 - 07.07.14 Use bl prefix for functions By: CTP
446 */
447 int blMparse(char *comline,
448  int nkeys,
449  MKeyWd *keywords,
450  REAL *floatparam,
451  char **strparam,
452  int *nparam)
453 {
454  char *command;
455  int i,n,found,nletters,nlett=0;
456 
457  command = blKillLeadSpaces(comline);
458  TERMINATE(command);
459 
460  if(command[0] == '$')
461  {
462  system(command+1);
463  return(PARSE_COMMENT);
464  }
465 
466  found = 0;
467  if((command[0]=='!') ||
468  (command[0]==LF) ||
469  (command[0]==CR) ||
470  (command[0]=='\0'))
471  return(PARSE_COMMENT);
472 
473  for(i=0;i<nkeys;i++)
474  {
475  /* match() returns 1 if first string finishes first or exact match
476  2 if second string finishes first
477  0 if a mismatch
478  We only want to act in the first case
479  */
480  if((n=blMatch(command,(keywords[i]).name,&nletters))==1)
481  {
482  if(found) /* If found already */
483  {
484  return(PARSE_ERRC);
485  }
486  found = i+1; /* +1, so keyword 0 will flag TRUE */
487  nlett = nletters;
488  }
489  }
490 
491  if(!found)
492  {
493  return(PARSE_ERRC);
494  }
495 
496  command+=nlett;
497  found--; /* Reset to point to the correct keyword */
498 
499  *nparam = 0; /* Zero the parameter count */
500 
501  /* Get data requirements for this keyword */
502  if((keywords[found]).string)
503  {
504  for(i=0; i<(keywords[found]).maxparam; i++)
505  {
506  command = blKillLeadSpaces(command);
507  if((nletters = blGetString(command,strparam[i]))==0)
508  {
509  if(i < (keywords[found]).minparam)
510  return(PARSE_ERRP);
511  else
512  break;
513  }
514  else
515  {
516  (*nparam)++;
517  }
518  command += nletters;
519  } /* End of for(i) */
520  }
521  else
522  {
523  /* A numeric or no parameter */
524  for(i=0; i<(keywords[found]).maxparam; i++)
525  {
526  command = blKillLeadSpaces(command);
527  if(!blGetParam(command,&(floatparam[i]),&nletters))
528  {
529  if(i < (keywords[found]).minparam)
530  return(PARSE_ERRP);
531  else
532  break;
533  }
534  command += nletters;
535  (*nparam)++;
536  } /* End of for(i) */
537  } /* End of else */
538  return(found);
539 }
540 
#define NULL
Definition: array2.c:99
void blStringToUpper(char *string1, char *string2)
#define PARSE_ERRC
Definition: parse.h:79
Include file for the command parser.
char * blKillLeadSpaces(char *string)
int blParse(char *comline, int nkeys, KeyWd *keywords, REAL *floatparam, char **strparam)
Definition: parse.c:202
Useful macros.
#define PARSE_ERRP
Definition: parse.h:80
#define TERMINATE(x)
Definition: macros.h:366
Definition: parse.h:92
double REAL
Definition: MathType.h:67
int blGetParam(char *command, REAL *value, int *nletters)
Definition: parse.c:412
int blMatch(char *comstring, char *string2, int *nletters)
Definition: parse.c:304
int blMparse(char *comline, int nkeys, MKeyWd *keywords, REAL *floatparam, char **strparam, int *nparam)
Definition: parse.c:447
Definition: parse.h:86
int blGetString(char *command, char *strparam)
Definition: parse.c:358
Header file for general purpose routines.
System-type variable type definitions.
#define PARSE_COMMENT
Definition: parse.h:81
Type definitions for maths.
#define LF
Definition: parse.c:175
#define CR
Definition: parse.c:176
#define DIC
Definition: parse.c:177