Implemented selections like "occupancy 0.5 to 1".
[gromacs/qmmm-gamess-us.git] / src / gmxlib / selection / params.c
blob50124a07a5fdb75ebe904a88d5c43d7b7b699d80
1 /*
3 * This source code is part of
5 * G R O M A C S
7 * GROningen MAchine for Chemical Simulations
9 * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
10 * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
11 * Copyright (c) 2001-2009, The GROMACS development team,
12 * check out http://www.gromacs.org for more information.
14 * This program is free software; you can redistribute it and/or
15 * modify it under the terms of the GNU General Public License
16 * as published by the Free Software Foundation; either version 2
17 * of the License, or (at your option) any later version.
19 * If you want to redistribute modifications, please consider that
20 * scientific software is very special. Version control is crucial -
21 * bugs must be traceable. We will be happy to consider code for
22 * inclusion in the official distribution, but derived work must not
23 * be called official GROMACS. Details are found in the README & COPYING
24 * files - if they are missing, get the official version at www.gromacs.org.
26 * To help us fund GROMACS development, we humbly ask that you cite
27 * the papers on the package - you can find them in the top README file.
29 * For more info, check our website at http://www.gromacs.org
31 /*! \internal \file
32 * \brief
33 * Implementation of functions in selparam.h.
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
39 #include <smalloc.h>
40 #include <string2.h>
41 #include <vec.h>
43 #include <position.h>
44 #include <selmethod.h>
45 #include <selparam.h>
47 #include "parsetree.h"
48 #include "position.h"
49 #include "selelem.h"
51 /*!
52 * \param[in] name Name of the parameter to search.
53 * \param[in] nparam Number of parameters in the \p param array.
54 * \param[in] param Parameter array to search.
55 * \returns Pointer to the parameter in the \p param
56 * or NULL if no parameter with name \p name was found.
58 * The comparison is case-sensitive.
60 gmx_ana_selparam_t *
61 gmx_ana_selparam_find(const char *name, int nparam, gmx_ana_selparam_t *param)
63 int i;
65 if (nparam == 0)
67 return NULL;
69 /* Find the first non-null parameter */
70 i = 0;
71 while (i < nparam && param[i].name == NULL)
73 ++i;
75 /* Process the special case of a NULL parameter */
76 if (name == NULL)
78 return (i == 0) ? NULL : &param[i-1];
80 for ( ; i < nparam; ++i)
82 if (!strcmp(param[i].name, name))
84 return &param[i];
86 /* Check for 'no' prefix on boolean parameters */
87 if (param[i].val.type == NO_VALUE
88 && strlen(name) > 2 && name[0] == 'n' && name[1] == 'o'
89 && !strcmp(param[i].name, name+2))
91 return &param[i];
94 return NULL;
97 /*! \brief
98 * Does a type conversion on a \c t_selexpr_value.
100 * \param[in,out] value Value to convert.
101 * \param[in] type Type to convert to.
102 * \param[in] scanner Scanner data structure.
103 * \returns 0 on success, a non-zero value on error.
105 static int
106 convert_value(t_selexpr_value *value, e_selvalue_t type, void *scanner)
108 if (value->type == type || type == NO_VALUE)
110 return 0;
112 if (value->bExpr)
114 /* Conversion from atom selection to position using default
115 * reference positions. */
116 if (value->type == GROUP_VALUE && type == POS_VALUE)
118 value->u.expr =
119 _gmx_sel_init_position(value->u.expr, NULL, FALSE, scanner);
120 if (value->u.expr == NULL)
122 return -1;
124 value->type = type;
125 return 0;
127 return -1;
129 else
131 /* Integers to floating point are easy */
132 if (value->type == INT_VALUE && type == REAL_VALUE)
134 value->u.r.r1 = (real)value->u.i.i1;
135 value->u.r.r2 = (real)value->u.i.i2;
136 value->type = type;
137 return 0;
139 /* Reals that are integer-valued can also be converted */
140 if (value->type == REAL_VALUE && type == INT_VALUE
141 && gmx_within_tol(value->u.r.r1, (int)value->u.r.r1, GMX_REAL_EPS)
142 && gmx_within_tol(value->u.r.r2, (int)value->u.r.r2, GMX_REAL_EPS))
144 value->u.i.i1 = (int)value->u.r.r1;
145 value->u.i.i2 = (int)value->u.r.r2;
146 value->type = type;
147 return 0;
150 return -1;
153 /*! \brief
154 * Does a type conversion on a list of values.
156 * \param[in,out] value Values to convert.
157 * \param[in] type Type to convert to.
158 * \param[in] scanner Scanner data structure.
159 * \returns 0 on success, a non-zero value on error.
161 static int
162 convert_values(t_selexpr_value *values, e_selvalue_t type, void *scanner)
164 t_selexpr_value *value;
165 int rc, rc1;
167 rc = 0;
168 value = values;
169 while (value)
171 rc1 = convert_value(value, type, scanner);
172 if (rc1 != 0 && rc == 0)
174 rc = rc1;
176 value = value->next;
178 /* FIXME: More informative error messages */
179 return rc;
182 /*! \brief
183 * Comparison function for sorting integer ranges.
185 * \param[in] a Pointer to the first range.
186 * \param[in] b Pointer to the second range.
187 * \returns -1, 0, or 1 depending on the relative order of \p a and \p b.
189 * The ranges are primarily sorted based on their starting point, and
190 * secondarily based on length (longer ranges come first).
192 static int
193 cmp_int_range(const void *a, const void *b)
195 if (((int *)a)[0] < ((int *)b)[0])
197 return -1;
199 if (((int *)a)[0] > ((int *)b)[0])
201 return 1;
203 if (((int *)a)[1] > ((int *)b)[1])
205 return -1;
207 return 0;
210 /*! \brief
211 * Comparison function for sorting real ranges.
213 * \param[in] a Pointer to the first range.
214 * \param[in] b Pointer to the second range.
215 * \returns -1, 0, or 1 depending on the relative order of \p a and \p b.
217 * The ranges are primarily sorted based on their starting point, and
218 * secondarily based on length (longer ranges come first).
220 static int
221 cmp_real_range(const void *a, const void *b)
223 if (((real *)a)[0] < ((real *)b)[0])
225 return -1;
227 if (((real *)a)[0] > ((real *)b)[0])
229 return 1;
231 if (((real *)a)[1] > ((real *)b)[1])
233 return -1;
235 return 0;
238 /*! \brief
239 * Parses the values for a parameter that takes integer or real ranges.
241 * \param[in] nval Number of values in \p values.
242 * \param[in] values Pointer to the list of values.
243 * \param param Parameter to parse.
244 * \returns TRUE if the values were parsed successfully, FALSE otherwise.
246 static bool
247 parse_values_range(int nval, t_selexpr_value *values, gmx_ana_selparam_t *param)
249 t_selexpr_value *value;
250 int *idata;
251 real *rdata;
252 int i, j, n;
254 param->flags &= ~SPAR_DYNAMIC;
255 if (param->val.type != INT_VALUE && param->val.type != REAL_VALUE)
257 gmx_bug("internal error");
258 return FALSE;
260 idata = NULL;
261 rdata = NULL;
262 if (param->val.type == INT_VALUE)
264 snew(idata, nval*2);
266 else
268 snew(rdata, nval*2);
270 value = values;
271 i = 0;
272 while (value)
274 if (value->bExpr)
276 _gmx_selparser_error("expressions not supported within range parameters");
277 return FALSE;
279 if (value->type != param->val.type)
281 gmx_bug("internal error");
282 return FALSE;
284 if (param->val.type == INT_VALUE)
286 /* Make sure the input range is in increasing order */
287 if (value->u.i.i1 > value->u.i.i2)
289 int tmp = value->u.i.i1;
290 value->u.i.i1 = value->u.i.i2;
291 value->u.i.i2 = tmp;
293 /* Check if the new range overlaps or extends the previous one */
294 if (i > 0 && value->u.i.i1 <= idata[i-1]+1 && value->u.i.i2 >= idata[i-2]-1)
296 idata[i-2] = min(idata[i-2], value->u.i.i1);
297 idata[i-1] = max(idata[i-1], value->u.i.i2);
299 else
301 idata[i++] = value->u.i.i1;
302 idata[i++] = value->u.i.i2;
305 else
307 /* Make sure the input range is in increasing order */
308 if (value->u.r.r1 > value->u.r.r2)
310 real tmp = value->u.r.r1;
311 value->u.r.r1 = value->u.r.r2;
312 value->u.r.r2 = tmp;
314 /* Check if the new range overlaps or extends the previous one */
315 if (i > 0 && value->u.r.r1 <= rdata[i-1] && value->u.r.r2 >= rdata[i-2])
317 rdata[i-2] = min(rdata[i-2], value->u.r.r1);
318 rdata[i-1] = max(rdata[i-1], value->u.r.r2);
320 else
322 rdata[i++] = value->u.r.r1;
323 rdata[i++] = value->u.r.r2;
326 value = value->next;
328 n = i/2;
329 /* Sort the ranges and merge consequent ones */
330 if (param->val.type == INT_VALUE)
332 qsort(idata, n, 2*sizeof(int), &cmp_int_range);
333 for (i = j = 2; i < 2*n; i += 2)
335 if (idata[j-1]+1 >= idata[i])
337 if (idata[i+1] > idata[j-1])
339 idata[j-1] = idata[i+1];
342 else
344 idata[j] = idata[i];
345 idata[j+1] = idata[i+1];
346 j += 2;
350 else
352 qsort(rdata, n, 2*sizeof(real), &cmp_real_range);
353 for (i = j = 2; i < 2*n; i += 2)
355 if (rdata[j-1]+1 >= rdata[i])
357 if (rdata[i+1] > rdata[j-1])
359 rdata[j-1] = rdata[i+1];
362 else
364 rdata[j] = rdata[i];
365 rdata[j+1] = rdata[i+1];
366 j += 2;
370 n = j/2;
371 /* Store the values */
372 if (param->flags & SPAR_VARNUM)
374 param->val.nr = n;
375 if (param->val.type == INT_VALUE)
377 srenew(idata, j);
378 _gmx_selvalue_setstore_alloc(&param->val, idata, j);
380 else
382 srenew(rdata, j);
383 _gmx_selvalue_setstore_alloc(&param->val, rdata, j);
386 else
388 if (n != param->val.nr)
390 _gmx_selparser_error("the value of parameter '%s' should consist of exactly one range",
391 param->name);
392 sfree(idata);
393 sfree(rdata);
394 return FALSE;
396 if (param->val.type == INT_VALUE)
398 memcpy(param->val.u.i, idata, 2*n*sizeof(int));
399 sfree(idata);
401 else
403 memcpy(param->val.u.r, rdata, 2*n*sizeof(real));
404 sfree(rdata);
407 if (param->nvalptr)
409 *param->nvalptr = param->val.nr;
411 param->nvalptr = NULL;
413 return TRUE;
416 /*! \brief
417 * Parses the values for a parameter that takes a variable number of values.
419 * \param[in] nval Number of values in \p values.
420 * \param[in] values Pointer to the list of values.
421 * \param param Parameter to parse.
422 * \returns TRUE if the values were parsed successfully, FALSE otherwise.
424 * For integer ranges, the sequence of numbers from the first to second value
425 * is stored, each as a separate value.
427 static bool
428 parse_values_varnum(int nval, t_selexpr_value *values, gmx_ana_selparam_t *param)
430 t_selexpr_value *value;
431 int i, j;
433 param->flags &= ~SPAR_DYNAMIC;
434 /* Update nval if there are integer ranges. */
435 if (param->val.type == INT_VALUE)
437 value = values;
438 while (value)
440 if (value->type == INT_VALUE && !value->bExpr)
442 nval += abs(value->u.i.i2 - value->u.i.i1);
444 value = value->next;
448 /* Check that the value type is actually implemented */
449 if (param->val.type != INT_VALUE && param->val.type != REAL_VALUE
450 && param->val.type != STR_VALUE && param->val.type != POS_VALUE)
452 gmx_bug("internal error");
453 return FALSE;
456 /* Reserve appropriate amount of memory */
457 if (param->val.type == POS_VALUE)
459 gmx_ana_pos_reserve(param->val.u.p, nval, 0);
460 gmx_ana_indexmap_init(&param->val.u.p->m, NULL, NULL, INDEX_UNKNOWN);
462 else
464 _gmx_selvalue_reserve(&param->val, nval);
467 value = values;
468 i = 0;
469 while (value)
471 if (value->bExpr)
473 _gmx_selparser_error("expressions not supported within value lists");
474 return FALSE;
476 if (value->type != param->val.type)
478 gmx_bug("internal error");
479 return FALSE;
481 switch (param->val.type)
483 case INT_VALUE:
484 if (value->u.i.i1 <= value->u.i.i2)
486 for (j = value->u.i.i1; j <= value->u.i.i2; ++j)
488 param->val.u.i[i++] = j;
491 else
493 for (j = value->u.i.i1; j >= value->u.i.i2; --j)
495 param->val.u.i[i++] = j;
498 break;
499 case REAL_VALUE:
500 if (value->u.r.r1 != value->u.r.r2)
502 _gmx_selparser_error("real ranges not supported for parameter '%s'", param->name);
503 return FALSE;
505 param->val.u.r[i++] = value->u.r.r1;
506 break;
507 case STR_VALUE: param->val.u.s[i++] = strdup(value->u.s); break;
508 case POS_VALUE: copy_rvec(value->u.x, param->val.u.p->x[i++]); break;
509 default: /* Should not be reached */
510 gmx_bug("internal error");
511 return FALSE;
513 value = value->next;
515 param->val.nr = i;
516 if (param->nvalptr)
518 *param->nvalptr = param->val.nr;
520 param->nvalptr = NULL;
522 return TRUE;
525 /*! \brief
526 * Adds a new subexpression reference to a selection element.
528 * \param[in,out] root Root element to which the subexpression is added.
529 * \param[in] param Parameter for which this expression is a value.
530 * \param[in] expr Expression to add.
531 * \returns The created child element.
533 * Creates a new \ref SEL_SUBEXPRREF element and adds it into the child
534 * list of \p root.
535 * If \p expr is already a \ref SEL_SUBEXPRREF, it is used as it is.
536 * \ref SEL_ALLOCVAL is cleared for the returned element.
538 static t_selelem *
539 add_child(t_selelem *root, gmx_ana_selparam_t *param, t_selelem *expr)
541 gmx_ana_selparam_t *ps;
542 int n;
543 t_selelem *child;
544 int rc;
546 if (root->type != SEL_EXPRESSION && root->type != SEL_MODIFIER)
548 gmx_bug("unsupported root element for selection parameter parser");
549 return NULL;
551 ps = root->u.expr.method->param;
552 n = param - ps;
553 /* Create a subexpression reference element if necessary */
554 if (expr->type == SEL_SUBEXPRREF)
556 child = expr;
558 else
560 child = _gmx_selelem_create(SEL_SUBEXPRREF);
561 if (!child)
563 return NULL;
565 _gmx_selelem_set_vtype(child, expr->v.type);
566 child->child = expr;
568 /* Setup the child element */
569 child->flags &= ~SEL_ALLOCVAL;
570 child->u.param = param;
571 if (child->v.type != param->val.type)
573 _gmx_selparser_error("invalid expression value for parameter '%s'",
574 param->name);
575 goto on_error;
577 rc = _gmx_selelem_update_flags(child);
578 if (rc != 0)
580 goto on_error;
582 if ((child->flags & SEL_DYNAMIC) && !(param->flags & SPAR_DYNAMIC))
584 _gmx_selparser_error("parameter '%s' does not support dynamic values",
585 param->name);
586 goto on_error;
588 if (!(child->flags & SEL_DYNAMIC))
590 param->flags &= ~SPAR_DYNAMIC;
592 /* Put the child element in the correct place */
593 if (!root->child || n < root->child->u.param - ps)
595 child->next = root->child;
596 root->child = child;
598 else
600 t_selelem *prev;
602 prev = root->child;
603 while (prev->next && prev->next->u.param - ps >= n)
605 prev = prev->next;
607 child->next = prev->next;
608 prev->next = child;
610 return child;
612 on_error:
613 if (child != expr)
615 _gmx_selelem_free(child);
617 return NULL;
620 /*! \brief
621 * Parses an expression value for a parameter that takes a variable number of values.
623 * \param[in] nval Number of values in \p values.
624 * \param[in] values Pointer to the list of values.
625 * \param param Parameter to parse.
626 * \param root Selection element to which child expressions are added.
627 * \returns TRUE if the values were parsed successfully, FALSE otherwise.
629 static bool
630 parse_values_varnum_expr(int nval, t_selexpr_value *values,
631 gmx_ana_selparam_t *param, t_selelem *root)
633 t_selexpr_value *value;
634 t_selelem *child;
635 t_selelem *expr;
637 if (nval != 1 || !values->bExpr)
639 gmx_bug("internal error");
640 return FALSE;
643 value = values;
644 child = add_child(root, param, value->u.expr);
645 value->u.expr = NULL;
646 if (!child)
648 return FALSE;
651 /* Process single-valued expressions */
652 /* TODO: We should also handle SEL_SINGLEVAL expressions here */
653 if (child->v.type == POS_VALUE || child->v.type == GROUP_VALUE)
655 /* Set the value storage */
656 _gmx_selvalue_setstore(&child->v, param->val.u.ptr);
657 param->val.nr = 1;
658 if (param->nvalptr)
660 *param->nvalptr = param->val.nr;
662 param->nvalptr = NULL;
663 return TRUE;
666 if (!(child->flags & SEL_VARNUMVAL))
668 _gmx_selparser_error("invalid expression value for parameter '%s'",
669 param->name);
670 return FALSE;
673 param->val.nr = -1;
674 *param->nvalptr = param->val.nr;
675 /* Rest of the initialization is done during compilation in
676 * init_method(). */
678 return TRUE;
681 /*! \brief
682 * Initializes the storage of an expression value.
684 * \param[in,out] sel Selection element that evaluates the value.
685 * \param[in] param Parameter to receive the value.
686 * \param[in] i The value of \p sel evaluates the value \p i for
687 * \p param.
689 * Initializes the data pointer of \p sel such that the result is stored
690 * as the value \p i of \p param.
691 * This function is used internally by parse_values_std().
693 static bool
694 set_expr_value_store(t_selelem *sel, gmx_ana_selparam_t *param, int i)
696 if (sel->v.type != GROUP_VALUE && !(sel->flags & SEL_SINGLEVAL))
698 _gmx_selparser_error("invalid expression value for parameter '%s'",
699 param->name);
700 return FALSE;
702 switch (sel->v.type)
704 case INT_VALUE: sel->v.u.i = &param->val.u.i[i]; break;
705 case REAL_VALUE: sel->v.u.r = &param->val.u.r[i]; break;
706 case STR_VALUE: sel->v.u.s = &param->val.u.s[i]; break;
707 case POS_VALUE: sel->v.u.p = &param->val.u.p[i]; break;
708 case GROUP_VALUE: sel->v.u.g = &param->val.u.g[i]; break;
709 default: /* Error */
710 gmx_bug("internal error");
711 return FALSE;
713 sel->v.nalloc = -1;
714 return TRUE;
717 /*! \brief
718 * Parses the values for a parameter that takes a constant number of values.
720 * \param[in] nval Number of values in \p values.
721 * \param[in] values Pointer to the list of values.
722 * \param param Parameter to parse.
723 * \param root Selection element to which child expressions are added.
724 * \returns TRUE if the values were parsed successfully, FALSE otherwise.
726 * For integer ranges, the sequence of numbers from the first to second value
727 * is stored, each as a separate value.
729 static bool
730 parse_values_std(int nval, t_selexpr_value *values, gmx_ana_selparam_t *param,
731 t_selelem *root)
733 t_selexpr_value *value;
734 t_selelem *child;
735 int i, j;
736 bool bDynamic;
738 /* Handle atom-valued parameters */
739 if (param->flags & SPAR_ATOMVAL)
741 if (nval > 1)
743 _gmx_selparser_error("extra values for parameter '%s'", param->name);
744 return FALSE;
746 value = values;
747 if (value->bExpr)
749 child = add_child(root, param, value->u.expr);
750 value->u.expr = NULL;
751 if (!child)
753 return FALSE;
755 if (child->v.type != GROUP_VALUE && (child->flags & SEL_ATOMVAL))
757 /* Rest of the initialization is done during compilation in
758 * init_method(). */
759 /* TODO: Positions are not correctly handled */
760 param->val.nr = -1;
761 if (param->nvalptr)
763 *param->nvalptr = -1;
765 return TRUE;
767 param->flags &= ~SPAR_ATOMVAL;
768 param->val.nr = 1;
769 if (param->nvalptr)
771 *param->nvalptr = 1;
773 param->nvalptr = NULL;
774 if (param->val.type == INT_VALUE || param->val.type == REAL_VALUE
775 || param->val.type == STR_VALUE)
777 _gmx_selvalue_reserve(&param->val, 1);
779 return set_expr_value_store(child, param, 0);
781 /* If we reach here, proceed with normal parameter handling */
782 param->val.nr = 1;
783 if (param->val.type == INT_VALUE || param->val.type == REAL_VALUE
784 || param->val.type == STR_VALUE)
786 _gmx_selvalue_reserve(&param->val, 1);
788 param->flags &= ~SPAR_ATOMVAL;
789 param->flags &= ~SPAR_DYNAMIC;
792 value = values;
793 i = 0;
794 bDynamic = FALSE;
795 while (value && i < param->val.nr)
797 if (value->type != param->val.type)
799 _gmx_selparser_error("incorrect value for parameter '%s' skipped", param->name);
800 value = value->next;
801 continue;
803 if (value->bExpr)
805 child = add_child(root, param, value->u.expr);
806 /* Clear the expression from the value once it is stored */
807 value->u.expr = NULL;
808 /* Check that the expression is valid */
809 if (!child)
811 return FALSE;
813 if (!set_expr_value_store(child, param, i))
815 return FALSE;
817 if (child->flags & SEL_DYNAMIC)
819 bDynamic = TRUE;
822 else
824 /* Value is not an expression */
825 switch (value->type)
827 case INT_VALUE:
828 if (value->u.i.i1 <= value->u.i.i2)
830 for (j = value->u.i.i1; j <= value->u.i.i2 && i < param->val.nr; ++j)
832 param->val.u.i[i++] = j;
834 if (j != value->u.i.i2 + 1)
836 _gmx_selparser_error("extra values for parameter '%s' skipped", param->name);
839 else
841 for (j = value->u.i.i1; j >= value->u.i.i2 && i < param->val.nr; --j)
843 param->val.u.i[i++] = j;
845 if (j != value->u.i.i2 - 1)
847 _gmx_selparser_error("extra values for parameter '%s' skipped", param->name);
850 --i;
851 break;
852 case REAL_VALUE:
853 if (value->u.r.r1 != value->u.r.r2)
855 _gmx_selparser_error("real ranges not supported for parameter '%s'", param->name);
856 return FALSE;
858 param->val.u.r[i] = value->u.r.r1;
859 break;
860 case STR_VALUE:
861 param->val.u.s[i] = strdup(value->u.s);
862 break;
863 case POS_VALUE:
864 gmx_ana_pos_init_const(&param->val.u.p[i], value->u.x);
865 break;
866 case NO_VALUE:
867 case GROUP_VALUE:
868 gmx_bug("internal error");
869 return FALSE;
872 ++i;
873 value = value->next;
875 if (value)
877 _gmx_selparser_error("extra values for parameter '%s'", param->name);
878 return FALSE;
880 if (i < param->val.nr)
882 _gmx_selparser_error("not enough values for parameter '%s'", param->name);
883 return FALSE;
885 if (!bDynamic)
887 param->flags &= ~SPAR_DYNAMIC;
889 if (param->nvalptr)
891 *param->nvalptr = param->val.nr;
893 param->nvalptr = NULL;
895 return TRUE;
898 /*! \brief
899 * Parses the values for a boolean parameter.
901 * \param[in] name Name by which the parameter was given.
902 * \param[in] nval Number of values in \p values.
903 * \param[in] values Pointer to the list of values.
904 * \param param Parameter to parse.
905 * \returns TRUE if the values were parsed successfully, FALSE otherwise.
907 static bool
908 parse_values_bool(const char *name, int nval, t_selexpr_value *values, gmx_ana_selparam_t *param)
910 bool bSetNo;
911 int len;
913 if (param->val.type != NO_VALUE)
915 gmx_bug("internal error");
916 return FALSE;
918 if (nval > 1 || (values && values->type != INT_VALUE))
920 _gmx_selparser_error("boolean parameter '%s' takes only a yes/no/on/off/0/1 value", param->name);
921 return FALSE;
924 bSetNo = FALSE;
925 /* Check if the parameter name is given with a 'no' prefix */
926 len = strlen(name);
927 if (len > 2 && name[0] == 'n' && name[1] == 'o'
928 && strncmp(name+2, param->name, len-2) == 0)
930 bSetNo = TRUE;
932 if (bSetNo && nval > 0)
934 _gmx_selparser_error("boolean parameter 'no%s' should not have a value", param->name);
935 return FALSE;
937 if (values && values->u.i.i1 == 0)
939 bSetNo = TRUE;
942 *param->val.u.b = bSetNo ? FALSE : TRUE;
943 return TRUE;
946 /*! \brief
947 * Parses the values for an enumeration parameter.
949 * \param[in] nval Number of values in \p values.
950 * \param[in] values Pointer to the list of values.
951 * \param param Parameter to parse.
952 * \returns TRUE if the values were parsed successfully, FALSE otherwise.
954 static bool
955 parse_values_enum(int nval, t_selexpr_value *values, gmx_ana_selparam_t *param)
957 int i, len, match;
959 if (nval != 1)
961 _gmx_selparser_error("a single value is required for parameter '%s'", param->name);
962 return FALSE;
964 if (values->type != STR_VALUE || param->val.type != STR_VALUE)
966 gmx_bug("internal error");
967 return FALSE;
969 if (values->bExpr)
971 _gmx_selparser_error("expression value for enumerated parameter '%s' not supported", param->name);
972 return FALSE;
975 len = strlen(values->u.s);
976 i = 1;
977 match = 0;
978 while (param->val.u.s[i] != NULL)
980 if (strncmp(values->u.s, param->val.u.s[i], len) == 0)
982 /* Check if there is a duplicate match */
983 if (match > 0)
985 _gmx_selparser_error("ambiguous value for parameter '%s'", param->name);
986 return FALSE;
988 match = i;
990 ++i;
992 if (match == 0)
994 _gmx_selparser_error("invalid value for parameter '%s'", param->name);
995 return FALSE;
997 param->val.u.s[0] = param->val.u.s[match];
998 return TRUE;
1001 /*! \brief
1002 * Replaces constant expressions with their values.
1004 * \param[in,out] values First element in the value list to process.
1006 static void
1007 convert_const_values(t_selexpr_value *values)
1009 t_selexpr_value *val;
1011 val = values;
1012 while (val)
1014 if (val->bExpr && val->u.expr->v.type != GROUP_VALUE &&
1015 val->u.expr->type == SEL_CONST)
1017 t_selelem *expr = val->u.expr;
1018 val->bExpr = FALSE;
1019 switch (expr->v.type)
1021 case INT_VALUE:
1022 val->u.i.i1 = val->u.i.i2 = expr->v.u.i[0];
1023 break;
1024 case REAL_VALUE:
1025 val->u.r.r1 = val->u.r.r2 = expr->v.u.r[0];
1026 break;
1027 case POS_VALUE:
1028 copy_rvec(expr->v.u.p->x[0], val->u.x);
1029 break;
1030 default:
1031 gmx_bug("internal error");
1032 break;
1034 _gmx_selelem_free(expr);
1036 val = val->next;
1041 * \param pparams List of parameters from the selection parser.
1042 * \param[in] nparam Number of parameters in \p params.
1043 * \param params Array of parameters to parse.
1044 * \param root Selection element to which child expressions are added.
1045 * \param[in] scanner Scanner data structure.
1046 * \returns TRUE if the parameters were parsed successfully, FALSE otherwise.
1048 * Initializes the \p params array based on the parameters in \p pparams.
1049 * See the documentation of \c gmx_ana_selparam_t for different options
1050 * available for parsing.
1052 * The list \p pparams and any associated values are freed after the parameters
1053 * have been processed, no matter is there was an error or not.
1055 bool
1056 _gmx_sel_parse_params(t_selexpr_param *pparams, int nparam, gmx_ana_selparam_t *params,
1057 t_selelem *root, void *scanner)
1059 t_selexpr_param *pparam;
1060 gmx_ana_selparam_t *oparam;
1061 bool bOk, rc;
1062 int i;
1064 /* Check that the value pointers of SPAR_VARNUM parameters are NULL and
1065 * that they are not NULL for other parameters */
1066 bOk = TRUE;
1067 for (i = 0; i < nparam; ++i)
1069 if (params[i].val.type != POS_VALUE && (params[i].flags & (SPAR_VARNUM | SPAR_ATOMVAL)))
1071 if (params[i].val.u.ptr != NULL)
1073 _gmx_selparser_error("warning: value pointer of parameter '%s' is not NULL\n"
1074 " although it should be for SPAR_VARNUM and SPAR_ATOMVAL parameters\n",
1075 params[i].name);
1077 if ((params[i].flags & SPAR_VARNUM)
1078 && (params[i].flags & SPAR_DYNAMIC) && !params[i].nvalptr)
1080 _gmx_selparser_error("error: nvalptr of parameter '%s' is NULL\n"
1081 " but both SPAR_VARNUM and SPAR_DYNAMIC are specified\n",
1082 params[i].name);
1083 bOk = FALSE;
1086 else
1088 if (params[i].val.u.ptr == NULL)
1090 _gmx_selparser_error("error: value pointer of parameter '%s' is NULL\n",
1091 params[i].name);
1092 bOk = FALSE;
1096 if (!bOk)
1098 _gmx_selexpr_free_params(pparams);
1099 return FALSE;
1101 /* Parse the parameters */
1102 pparam = pparams;
1103 i = 0;
1104 while (pparam)
1106 /* Find the parameter and make some checks */
1107 if (pparam->name != NULL)
1109 i = -1;
1110 oparam = gmx_ana_selparam_find(pparam->name, nparam, params);
1112 else if (i >= 0)
1114 oparam = &params[i];
1115 if (oparam->name != NULL)
1117 oparam = NULL;
1118 _gmx_selparser_error("too many NULL parameters provided");
1119 bOk = FALSE;
1120 goto next_param;
1122 ++i;
1124 else
1126 _gmx_selparser_error("all NULL parameters should appear in the beginning of the list");
1127 bOk = FALSE;
1128 pparam = pparam->next;
1129 continue;
1131 if (!oparam)
1133 _gmx_selparser_error("unknown parameter '%s' skipped", pparam->name);
1134 bOk = FALSE;
1135 goto next_param;
1137 if (oparam->flags & SPAR_SET)
1139 _gmx_selparser_error("parameter '%s' set multiple times, extra values skipped", pparam->name);
1140 bOk = FALSE;
1141 goto next_param;
1143 oparam->flags |= SPAR_SET;
1144 /* Process the values for the parameter */
1145 convert_const_values(pparam->value);
1146 if (convert_values(pparam->value, oparam->val.type, scanner) != 0)
1148 _gmx_selparser_error("invalid value for parameter '%s'", pparam->name);
1149 bOk = FALSE;
1150 goto next_param;
1152 if (oparam->val.type == NO_VALUE)
1154 rc = parse_values_bool(pparam->name, pparam->nval, pparam->value, oparam);
1156 else if (oparam->flags & SPAR_RANGES)
1158 rc = parse_values_range(pparam->nval, pparam->value, oparam);
1160 else if (oparam->flags & SPAR_VARNUM)
1162 if (pparam->nval == 1 && pparam->value->bExpr)
1164 rc = parse_values_varnum_expr(pparam->nval, pparam->value, oparam, root);
1166 else
1168 rc = parse_values_varnum(pparam->nval, pparam->value, oparam);
1171 else if (oparam->flags & SPAR_ENUMVAL)
1173 rc = parse_values_enum(pparam->nval, pparam->value, oparam);
1175 else
1177 rc = parse_values_std(pparam->nval, pparam->value, oparam, root);
1179 if (!rc)
1181 bOk = FALSE;
1183 /* Advance to the next parameter */
1184 next_param:
1185 pparam = pparam->next;
1187 /* Check that all required parameters are present */
1188 for (i = 0; i < nparam; ++i)
1190 if (!(params[i].flags & SPAR_OPTIONAL) && !(params[i].flags & SPAR_SET))
1192 _gmx_selparser_error("required parameter '%s' not specified", params[i].name);
1193 bOk = FALSE;
1197 _gmx_selexpr_free_params(pparams);
1198 return bOk;