/*
+ * This file is part of the GROMACS molecular simulation package.
*
- * This source code is part of
+ * Copyright (c) 2009,2010,2011,2012,2014, by the GROMACS development team, led by
+ * Mark Abraham, David van der Spoel, Berk Hess, and Erik Lindahl,
+ * and including many others, as listed in the AUTHORS file in the
+ * top-level source directory and at http://www.gromacs.org.
*
- * G R O M A C S
+ * GROMACS is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 2.1
+ * of the License, or (at your option) any later version.
*
- * GROningen MAchine for Chemical Simulations
+ * GROMACS is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
*
- * Written by David van der Spoel, Erik Lindahl, Berk Hess, and others.
- * Copyright (c) 1991-2000, University of Groningen, The Netherlands.
- * Copyright (c) 2001-2009, The GROMACS development team,
- * check out http://www.gromacs.org for more information.
-
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GROMACS; if not, see
+ * http://www.gnu.org/licenses, or write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
- * If you want to redistribute modifications, please consider that
- * scientific software is very special. Version control is crucial -
- * bugs must be traceable. We will be happy to consider code for
- * inclusion in the official distribution, but derived work must not
- * be called official GROMACS. Details are found in the README & COPYING
- * files - if they are missing, get the official version at www.gromacs.org.
+ * If you want to redistribute modifications to GROMACS, please
+ * consider that scientific software is very special. Version
+ * control is crucial - bugs must be traceable. We will be happy to
+ * consider code for inclusion in the official distribution, but
+ * derived work must not be called official GROMACS. Details are found
+ * in the README & COPYING files - if they are missing, get the
+ * official version at http://www.gromacs.org.
*
* To help us fund GROMACS development, we humbly ask that you cite
- * the papers on the package - you can find them in the top README file.
- *
- * For more info, check our website at http://www.gromacs.org
+ * the research papers on the package. Check out http://www.gromacs.org.
*/
/*! \internal \file
* \brief
* Implements functions in selmethod.h.
*
- * \author Teemu Murtola <teemu.murtola@cbr.su.se>
+ * \author Teemu Murtola <teemu.murtola@gmail.com>
* \ingroup module_selection
*/
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "gmxpre.h"
+
+#include "selmethod.h"
#include <ctype.h>
#include <stdarg.h>
-#include <macros.h>
-#include <string2.h>
-
-#include "gromacs/selection/selmethod.h"
+#include "gromacs/legacyheaders/macros.h"
+#include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/exceptions.h"
#include "symrec.h"
extern gmx_ana_selmethod_t sm_resindex;
extern gmx_ana_selmethod_t sm_molindex;
extern gmx_ana_selmethod_t sm_atomname;
+extern gmx_ana_selmethod_t sm_pdbatomname;
extern gmx_ana_selmethod_t sm_atomtype;
extern gmx_ana_selmethod_t sm_resname;
extern gmx_ana_selmethod_t sm_insertcode;
{"mol", &sm_molindex},
{"molecule", &sm_molindex},
{NULL, &sm_atomname},
+ {"name", &sm_atomname},
+ {NULL, &sm_pdbatomname},
+ {"pdbname", &sm_pdbatomname},
{NULL, &sm_atomtype},
+ {"type", &sm_atomtype},
{NULL, &sm_resname},
{NULL, &sm_insertcode},
{NULL, &sm_chain},
* \param[in] name Name of the method (used for error messages).
* \param[in] nparams Number of parameters in \p param.
* \param[in,out] param Parameter array
- * (only the \c flags field of gmx_boolean parameters may be modified).
+ * (only the \c flags field of boolean parameters may be modified).
* \param[in] symtab Symbol table (used for checking overlaps).
- * \returns TRUE if there are no problems with the parameters,
- * FALSE otherwise.
+ * \returns true if there are no problems with the parameters,
+ * false otherwise.
*
* This function performs some checks common to both check_method() and
* check_modifier().
* If you remove a check, make sure that the parameter parser can handle the
* resulting parameters.
*/
-static gmx_bool
+static bool
check_params(FILE *fp, const char *name, int nparams, gmx_ana_selparam_t param[],
- gmx_sel_symtab_t *symtab)
+ const gmx::SelectionParserSymbolTable &symtab)
{
- gmx_bool bOk = TRUE;
- gmx_sel_symrec_t *sym;
+ bool bOk = true;
int i, j;
if (nparams > 0 && !param)
{
report_error(fp, name, "error: missing parameter data");
- bOk = FALSE;
- return FALSE;
+ return false;
}
if (nparams == 0 && param)
{
if (param[i].name == NULL && i > 0)
{
report_error(fp, name, "error: NULL parameter should be the first one");
- bOk = FALSE;
+ bOk = false;
continue;
}
/* Check for duplicates */
if (!gmx_strcasecmp(param[i].name, param[j].name))
{
report_error(fp, name, "error: duplicate parameter name '%s'", param[i].name);
- bOk = FALSE;
+ bOk = false;
break;
}
}
if (param[i].val.type != INT_VALUE && param[i].val.type != REAL_VALUE)
{
report_param_error(fp, name, param[i].name, "error: SPAR_RANGES cannot be set for a non-numeric parameter");
- bOk = FALSE;
+ bOk = false;
}
if (param[i].flags & SPAR_DYNAMIC)
{
if (!(param[i].flags & SPAR_VARNUM) && param[i].val.nr != 1)
{
report_param_error(fp, name, param[i].name, "error: range should take either one or an arbitrary number of values");
- bOk = FALSE;
+ bOk = false;
}
if (param[i].flags & SPAR_ATOMVAL)
{
report_param_error(fp, name, param[i].name, "error: SPAR_RANGES and SPAR_ATOMVAL both set");
- bOk = FALSE;
+ bOk = false;
}
}
if ((param[i].flags & SPAR_VARNUM) && (param[i].flags & SPAR_ATOMVAL))
{
report_param_error(fp, name, param[i].name, "error: SPAR_VARNUM and SPAR_ATOMVAL both set");
- bOk = FALSE;
+ bOk = false;
}
if (param[i].flags & SPAR_ENUMVAL)
{
if (param[i].val.type != STR_VALUE)
{
report_param_error(fp, name, param[i].name, "error: SPAR_ENUMVAL can only be set for string parameters");
- bOk = FALSE;
+ bOk = false;
}
if (param[i].val.nr != 1)
{
report_param_error(fp, name, param[i].name, "error: SPAR_ENUMVAL parameters should take exactly one value");
- bOk = FALSE;
+ bOk = false;
}
if (param[i].flags & (SPAR_DYNAMIC | SPAR_VARNUM | SPAR_ATOMVAL))
{
report_param_error(fp, name, param[i].name, "error: only SPAR_OPTIONAL supported with SPAR_ENUMVAL");
- bOk = FALSE;
+ bOk = false;
}
}
- /* Check gmx_boolean parameters */
+ /* Check boolean parameters */
if (param[i].val.type == NO_VALUE)
{
if (param[i].val.nr != 0)
{
- report_param_error(fp, name, param[i].name, "error: number of values should be zero for gmx_boolean parameters");
- bOk = FALSE;
+ report_param_error(fp, name, param[i].name, "error: number of values should be zero for boolean parameters");
+ bOk = false;
}
- /* The gmx_boolean parameters should always be optional, so set the
+ /* The boolean parameters should always be optional, so set the
* flag for convenience. */
param[i].flags |= SPAR_OPTIONAL;
/* Any other flags should not be specified */
if (param[i].flags & ~SPAR_OPTIONAL)
{
- report_param_error(fp, name, param[i].name, "error: gmx_boolean parameter should not have any flags set");
- bOk = FALSE;
+ report_param_error(fp, name, param[i].name, "error: boolean parameter should not have any flags set");
+ bOk = false;
}
}
/* Check val.nr */
if (param[i].val.nr <= 0)
{
report_param_error(fp, name, param[i].name, "error: val.nr <= 0");
- bOk = FALSE;
+ bOk = false;
}
}
/* Check that the value pointer is NULL */
if (!isalpha(param[i].name[0]))
{
report_param_error(fp, name, param[i].name, "error: name does not begin with a letter");
- bOk = FALSE;
+ bOk = false;
continue;
}
for (j = 1; param[i].name[j] != 0; ++j)
if (param[i].name[j] != '_' && !isalnum(param[i].name[j]))
{
report_param_error(fp, name, param[i].name, "error: name contains non-alphanumeric characters");
- bOk = FALSE;
+ bOk = false;
break;
}
}
continue;
}
/* Check that the name does not conflict with a method */
- if (_gmx_sel_find_symbol(symtab, param[i].name, TRUE))
+ if (symtab.findSymbol(param[i].name, true))
{
report_param_error(fp, name, param[i].name, "error: name conflicts with another method or a keyword");
- bOk = FALSE;
+ bOk = false;
}
} /* End of parameter loop */
- /* Check parameters of existing methods */
- sym = _gmx_sel_first_symbol(symtab, SYMBOL_METHOD);
- while (sym)
+ /* Check parameters of existing methods */
+ gmx::SelectionParserSymbolIterator symbol
+ = symtab.beginIterator(gmx::SelectionParserSymbol::MethodSymbol);
+ while (symbol != symtab.endIterator())
{
- gmx_ana_selmethod_t *method = _gmx_sel_sym_value_method(sym);
- gmx_ana_selparam_t *param =
+ gmx_ana_selmethod_t *method = symbol->methodValue();
+ gmx_ana_selparam_t *param =
gmx_ana_selmethod_find_param(name, method);
if (param)
{
report_param_error(fp, method->name, param->name, "error: name conflicts with another method or a keyword");
- bOk = FALSE;
+ bOk = false;
}
- sym = _gmx_sel_next_symbol(sym, SYMBOL_METHOD);
+ ++symbol;
}
return bOk;
}
* \param[in] fp File handle to use for diagnostic messages
* (can be NULL).
* \param[in] method The method to check.
- * \returns TRUE if there are no problems, FALSE otherwise.
+ * \returns true if there are no problems, false otherwise.
*
* This function performs some checks common to both check_method() and
* check_modifier().
* This function checks that all the required callbacks are defined, i.e.,
* not NULL, to find programming errors.
*/
-static gmx_bool
+static bool
check_callbacks(FILE *fp, gmx_ana_selmethod_t *method)
{
- gmx_bool bOk = TRUE;
- gmx_bool bNeedInit;
+ bool bOk = true;
+ bool bNeedInit;
int i;
/* Make some checks on init_data and free */
if (method->nparams > 0 && !method->init_data)
{
report_error(fp, method->name, "error: init_data should be provided because the method has parameters");
- bOk = FALSE;
+ bOk = false;
}
if (method->free && !method->init_data)
{
if (method->type == POS_VALUE && !method->outinit)
{
report_error(fp, method->name, "error: outinit should be provided because the method has POS_VALUE");
- bOk = FALSE;
+ bOk = false;
+ }
+ /* Check presence of outinit for variable output count methods */
+ if ((method->flags & SMETH_VARNUMVAL) && !method->outinit)
+ {
+ report_error(fp, method->name, "error: outinit should be provided because the method has SMETH_VARNUMVAL");
+ bOk = false;
}
/* Warn of dynamic callbacks in static methods */
if (!(method->flags & SMETH_MODIFIER))
if (method->type != NO_VALUE && !method->update && !method->pupdate)
{
report_error(fp, method->name, "error: evaluation function missing");
- bOk = FALSE;
+ bOk = false;
}
/* Loop through the parameters to determine if initialization callbacks
* are needed. */
- bNeedInit = FALSE;
+ bNeedInit = false;
for (i = 0; i < method->nparams; ++i)
{
if (method->param[i].val.type != POS_VALUE
&& (method->param[i].flags & (SPAR_VARNUM | SPAR_ATOMVAL)))
{
- bNeedInit = TRUE;
+ bNeedInit = true;
}
}
/* Check that the callbacks required by the parameters are present */
if (bNeedInit && !method->init)
{
report_error(fp, method->name, "error: init should be provided");
- bOk = FALSE;
+ bOk = false;
}
return bOk;
}
-/*!
+/*! \brief
* Checks the validity of a selection method.
*
* \param[in] fp File handle to use for diagnostic messages
* If you remove a check, please make sure that the selection parser,
* compiler, and evaluation functions can deal with the method.
*/
-static gmx_bool
-check_method(FILE *fp, gmx_ana_selmethod_t *method, gmx_sel_symtab_t *symtab)
+static bool
+check_method(FILE *fp, gmx_ana_selmethod_t *method,
+ const gmx::SelectionParserSymbolTable &symtab)
{
- gmx_bool bOk = TRUE;
+ bool bOk = true;
/* Check the type */
if (method->type == NO_VALUE)
{
report_error(fp, method->name, "error: no value type specified");
- bOk = FALSE;
+ bOk = false;
}
if (method->type == STR_VALUE && method->nparams > 0)
{
report_error(fp, method->name, "error: evaluates to a string but is not a keyword");
- bOk = FALSE;
+ bOk = false;
}
/* Check flags */
if (method->type == GROUP_VALUE)
if (method->flags & SMETH_VARNUMVAL)
{
report_error(fp, method->name, "error: SMETH_VARNUMVAL cannot be set for group-valued methods");
- bOk = FALSE;
+ bOk = false;
}
}
else
&& (method->flags & SMETH_VARNUMVAL))
{
report_error(fp, method->name, "error: SMETH_SINGLEVAL and SMETH_VARNUMVAL both set");
- bOk = FALSE;
+ bOk = false;
}
}
if ((method->flags & SMETH_CHARVAL) && method->type != STR_VALUE)
{
report_error(fp, method->name, "error: SMETH_CHARVAL can only be specified for STR_VALUE methods");
- bOk = FALSE;
+ bOk = false;
}
/* Check the parameters */
if (!check_params(fp, method->name, method->nparams, method->param, symtab))
{
- bOk = FALSE;
+ bOk = false;
}
/* Check the callback pointers */
if (!check_callbacks(fp, method))
{
- bOk = FALSE;
+ bOk = false;
}
return bOk;
}
-/*!
+/*! \brief
* Checks the validity of a selection modifier method.
*
* \param[in] fp File handle to use for diagnostic messages
* If you remove a check, please make sure that the selection parser,
* compiler, and evaluation functions can deal with the method.
*/
-static gmx_bool
-check_modifier(FILE *fp, gmx_ana_selmethod_t *method, gmx_sel_symtab_t *symtab)
+static bool
+check_modifier(FILE *fp, gmx_ana_selmethod_t *method,
+ const gmx::SelectionParserSymbolTable &symtab)
{
- gmx_bool bOk = TRUE;
+ bool bOk = true;
/* Check the type */
if (method->type != NO_VALUE && method->type != POS_VALUE)
{
report_error(fp, method->name, "error: modifier should have type POS_VALUE or NO_VALUE");
- bOk = FALSE;
+ bOk = false;
}
/* Check flags */
if (method->flags & (SMETH_SINGLEVAL | SMETH_VARNUMVAL))
{
report_error(fp, method->name, "error: modifier should not have SMETH_SINGLEVAL or SMETH_VARNUMVAL set");
- bOk = FALSE;
+ bOk = false;
}
/* Check the parameters */
/* The first parameter is skipped */
if (!check_params(fp, method->name, method->nparams-1, method->param+1, symtab))
{
- bOk = FALSE;
+ bOk = false;
}
/* Check the callback pointers */
if (!check_callbacks(fp, method))
{
- bOk = FALSE;
+ bOk = false;
}
if (method->update)
{
report_error(fp, method->name, "error: modifier should not have update");
- bOk = FALSE;
+ bOk = false;
}
if (method->type == POS_VALUE && !method->pupdate)
{
report_error(fp, method->name, "error: evaluation function missing");
- bOk = FALSE;
+ bOk = false;
}
return bOk;
* All problems are described to \p stderr.
*/
int
-gmx_ana_selmethod_register(gmx_sel_symtab_t *symtab,
+gmx_ana_selmethod_register(gmx::SelectionParserSymbolTable *symtab,
const char *name, gmx_ana_selmethod_t *method)
{
- gmx_bool bOk;
+ bool bOk;
/* Check the method */
if (method->flags & SMETH_MODIFIER)
{
- bOk = check_modifier(stderr, method, symtab);
+ bOk = check_modifier(stderr, method, *symtab);
}
else
{
- bOk = check_method(stderr, method, symtab);
+ bOk = check_method(stderr, method, *symtab);
}
/* Try to register the method if everything is ok */
- if (bOk)
+ if (bOk)
{
- if (!_gmx_sel_add_method_symbol(symtab, name, method))
+ try
+ {
+ symtab->addMethod(name, method);
+ }
+ catch (const gmx::APIError &ex)
{
- bOk = FALSE;
+ report_error(stderr, name, ex.what());
+ bOk = false;
}
}
if (!bOk)
* registered.
*/
int
-gmx_ana_selmethod_register_defaults(gmx_sel_symtab_t *symtab)
+gmx_ana_selmethod_register_defaults(gmx::SelectionParserSymbolTable *symtab)
{
size_t i;
- int rc;
- gmx_bool bOk;
+ int rc;
+ bool bOk;
- bOk = TRUE;
+ bOk = true;
for (i = 0; i < asize(smtable_def); ++i)
{
gmx_ana_selmethod_t *method = smtable_def[i].method;
}
if (rc != 0)
{
- bOk = FALSE;
+ bOk = false;
}
}
return bOk ? 0 : -1;