Sort all includes in src/gromacs
[alexxy/gromacs.git] / src / gromacs / selection / sm_keywords.cpp
index 9c777e21b47ced5466bb173052568754df76d663..32d478ed00bfd63ae5f1de79aba80027d0721198 100644 (file)
 /*
+ * This file is part of the GROMACS molecular simulation package.
  *
- *                This source code is part of
+ * Copyright (c) 2009,2010,2011,2012,2013,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 internal selection methods for numeric and string keyword
  * evaluation.
  *
- * \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 <ctype.h>
-#ifdef HAVE_SYS_TYPES_H
-#include <sys/types.h>  /*old Mac needs types before regex.h*/
-#endif
-#ifdef HAVE_REGEX_H
-#include <regex.h>
-#define USE_REGEX
-#endif
-
-#include "macros.h"
-#include "smalloc.h"
-#include "string2.h"
-
-#include "gromacs/selection/selmethod.h"
-#include "gromacs/utility/errorcodes.h"
+#include "gmxpre.h"
+
+#include <cctype>
+#include <cstring>
+
+#include <string>
+
+#include <boost/shared_ptr.hpp>
+
+#include "gromacs/legacyheaders/macros.h"
+#include "gromacs/utility/cstringutil.h"
+#include "gromacs/utility/exceptions.h"
+#include "gromacs/utility/gmxregex.h"
 #include "gromacs/utility/messagestringcollector.h"
+#include "gromacs/utility/smalloc.h"
+#include "gromacs/utility/stringutil.h"
 
 #include "keywords.h"
 #include "parsetree.h"
 #include "scanner.h"
 #include "selelem.h"
+#include "selmethod.h"
 
-/** Allocates data for integer keyword evaluation. */
+/*! \brief
+ * Allocates data for integer keyword evaluation.
+ *
+ * \param[in] npar  Not used.
+ * \param     param Not used.
+ * \returns   Pointer to the allocated data (\ref t_methoddata_kwint).
+ *
+ * Allocates memory for a \ref t_methoddata_kwint structure.
+ */
 static void *
-init_data_kwint(int npar, gmx_ana_selparam_t *param);
-/** Allocates data for real keyword evaluation. */
+init_data_kwint(int  npar, gmx_ana_selparam_t * param);
+/*! \brief
+ * Allocates data for real keyword evaluation.
+ *
+ * \param[in] npar  Not used.
+ * \param     param Not used.
+ * \returns   Pointer to the allocated data (\ref t_methoddata_kwreal).
+ *
+ * Allocates memory for a \ref t_methoddata_kwreal structure.
+ */
 static void *
-init_data_kwreal(int npar, gmx_ana_selparam_t *param);
-/** Allocates data for string keyword evaluation. */
+init_data_kwreal(int npar, gmx_ana_selparam_t * param);
+/*! \brief
+ * Allocates data for string keyword evaluation.
+ *
+ * \param[in] npar  Not used.
+ * \param     param Not used.
+ * \returns Pointer to the allocated data (t_methoddata_kwstr).
+ *
+ * Allocates memory for a t_methoddata_kwstr structure.
+ */
 static void *
-init_data_kwstr(int npar, gmx_ana_selparam_t *param);
-/** Initializes data for integer keyword evaluation. */
+init_data_kwstr(int npar, gmx_ana_selparam_t * param);
+/** /brief Initializes data for integer keyword evaluation.
+ *
+ * \param[in] top   Not used.
+ * \param[in] npar  Not used (should be 2).
+ * \param[in] param Method parameters (should point to \ref smparams_keyword_int).
+ * \param[in] data  Should point to \ref t_methoddata_kwint.
+ */
 static void
 init_kwint(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
-/** Initializes data for real keyword evaluation. */
+/*! \brief
+ * Initializes data for real keyword evaluation.
+ *
+ * \param[in] top   Not used.
+ * \param[in] npar  Not used (should be 2).
+ * \param[in] param Method parameters (should point to \ref smparams_keyword_real).
+ * \param[in] data  Should point to \ref t_methoddata_kwreal.
+ * \returns   0 (the initialization always succeeds).
+ */
 static void
 init_kwreal(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
-/** Initializes data for string keyword evaluation. */
+/*! \brief
+ * Initializes data for string keyword evaluation.
+ *
+ * \param[in] top   Not used.
+ * \param[in] npar  Not used (should be 2).
+ * \param[in] param Method parameters (should point to \ref smparams_keyword_str).
+ * \param[in] data  Should point to t_methoddata_kwstr.
+ */
 static void
 init_kwstr(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
 /** Frees the memory allocated for string keyword evaluation. */
@@ -85,15 +131,15 @@ static void
 free_data_kwstr(void *data);
 /** Evaluates integer selection keywords. */
 static void
-evaluate_keyword_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_keyword_int(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /** Evaluates real selection keywords. */
 static void
-evaluate_keyword_real(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_keyword_real(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
                       gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 /** Evaluates string selection keywords. */
 static void
-evaluate_keyword_str(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_keyword_str(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
 
 /*! \internal \brief
@@ -134,33 +180,96 @@ typedef struct t_methoddata_kwreal
     real              *r;
 } t_methoddata_kwreal;
 
+namespace
+{
+
+/*! \internal \brief
+ * Single item in the list of strings/regular expressions to match.
+ *
+ * \ingroup module_selection
+ */
+class StringKeywordMatchItem
+{
+    public:
+        /*! \brief
+         * Constructs a matcher from a string.
+         *
+         * \param[in] matchType String matching type.
+         * \param[in] str       String to use for matching.
+         */
+        StringKeywordMatchItem(gmx::SelectionStringMatchType matchType,
+                               const char                   *str)
+            : str_(str)
+        {
+            bool bRegExp = (matchType == gmx::eStringMatchType_RegularExpression);
+            if (matchType == gmx::eStringMatchType_Auto)
+            {
+                for (size_t j = 0; j < std::strlen(str); ++j)
+                {
+                    if (std::ispunct(str[j]) && str[j] != '?' && str[j] != '*')
+                    {
+                        bRegExp = true;
+                        break;
+                    }
+                }
+            }
+            if (bRegExp)
+            {
+                if (!gmx::Regex::isSupported())
+                {
+                    GMX_THROW(gmx::InvalidInputError(gmx::formatString(
+                                                             "No regular expression support, "
+                                                             "cannot match \"%s\"", str)));
+                }
+                regex_.reset(new gmx::Regex(str));
+            }
+        }
+
+        /*! \brief
+         * Checks whether this item matches a string.
+         *
+         * \param[in] matchType String matching type.
+         * \param[in] value     String to match.
+         * \returns   true if this item matches \p value.
+         */
+        bool match(gmx::SelectionStringMatchType matchType,
+                   const char                   *value) const
+        {
+            if (matchType == gmx::eStringMatchType_Exact)
+            {
+                return str_ == value;
+            }
+            else if (regex_)
+            {
+                return gmx::regexMatch(value, *regex_);
+            }
+            else
+            {
+                return gmx_wcmatch(str_.c_str(), value) == 0;
+            }
+        }
+
+    private:
+        //! The raw string passed for the matcher.
+        std::string                     str_;
+        //! Regular expression compiled from \p str_, if applicable.
+        boost::shared_ptr<gmx::Regex>   regex_;
+};
+
 /*! \internal \brief
  * Data structure for string keyword expression evaluation.
  */
-typedef struct t_methoddata_kwstr
+struct t_methoddata_kwstr
 {
+    /** Matching type for the strings. */
+    gmx::SelectionStringMatchType       matchType;
     /** Array of values for the keyword. */
-    char             **v;
-    /** Number of elements in the \p val array. */
-    int                n;
-    /*! \internal \brief
-     * Array of strings/regular expressions to match against.
-     */
-    struct t_methoddata_kwstr_match {
-        /** true if the expression is a regular expression, false otherwise. */
-        bool           bRegExp;
-        /** The value to match against. */
-        union {
-#ifdef USE_REGEX
-            /** Compiled regular expression if \p bRegExp is true. */
-            regex_t    r;
-#endif
-            /** The string if \p bRegExp is false; */
-            char      *s;
-        }              u;
-    }                 *m;
-    /**< Array of strings/regular expressions to match against.*/
-} t_methoddata_kwstr;
+    char                              **v;
+    /** Array of strings/regular expressions to match against.*/
+    std::vector<StringKeywordMatchItem> matches;
+};
+
+} // namespace
 
 /** Parameters for integer keyword evaluation. */
 static gmx_ana_selparam_t smparams_keyword_int[] = {
@@ -180,55 +289,72 @@ static gmx_ana_selparam_t smparams_keyword_str[] = {
     {NULL, {STR_VALUE, -1, {NULL}}, NULL, SPAR_VARNUM},
 };
 
-/** \internal Selection method data for integer keyword evaluation. */
+/** Selection method data for integer keyword evaluation. */
 gmx_ana_selmethod_t sm_keyword_int = {
     "kw_int", GROUP_VALUE, SMETH_SINGLEVAL,
     asize(smparams_keyword_int), smparams_keyword_int,
     &init_data_kwint,
-     NULL,
+    NULL,
     &init_kwint,
-     NULL,
-     NULL,
-     NULL,
+    NULL,
+    NULL,
+    NULL,
     &evaluate_keyword_int,
-     NULL,
+    NULL,
     {NULL, 0, NULL},
 };
 
-/** \internal Selection method data for real keyword evaluation. */
+/** Selection method data for real keyword evaluation. */
 gmx_ana_selmethod_t sm_keyword_real = {
     "kw_real", GROUP_VALUE, SMETH_SINGLEVAL,
     asize(smparams_keyword_real), smparams_keyword_real,
     &init_data_kwreal,
-     NULL,
+    NULL,
     &init_kwreal,
-     NULL,
-     NULL,
-     NULL,
+    NULL,
+    NULL,
+    NULL,
     &evaluate_keyword_real,
-     NULL,
+    NULL,
     {NULL, 0, NULL},
 };
 
-/** \internal Selection method data for string keyword evaluation. */
+/** Selection method data for string keyword evaluation. */
 gmx_ana_selmethod_t sm_keyword_str = {
     "kw_str", GROUP_VALUE, SMETH_SINGLEVAL,
     asize(smparams_keyword_str), smparams_keyword_str,
     &init_data_kwstr,
-     NULL,
+    NULL,
     &init_kwstr,
-     NULL,
+    NULL,
     &free_data_kwstr,
-     NULL,
+    NULL,
     &evaluate_keyword_str,
-     NULL,
+    NULL,
     {NULL, 0, NULL},
 };
 
-/** Initializes keyword evaluation for an arbitrary group. */
+/*! \brief
+ * Initializes keyword evaluation for an arbitrary group.
+ *
+ * \param[in] top   Not used.
+ * \param[in] npar  Not used.
+ * \param[in] param Not used.
+ * \param[in] data  Should point to \ref t_methoddata_kweval.
+ * \returns   0 on success, a non-zero error code on return.
+ *
+ * Calls the initialization method of the wrapped keyword.
+ */
 static void
-init_kweval(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
-/** Initializes output for keyword evaluation in an arbitrary group. */
+init_kweval(t_topology *top, int npar, gmx_ana_selparam_t * param, void *data);
+/*! \brief
+ * Initializes output for keyword evaluation in an arbitrary group.
+ *
+ * \param[in]     top   Not used.
+ * \param[in,out] out   Pointer to output data structure.
+ * \param[in,out] data  Should point to \c t_methoddata_kweval.
+ * \returns       0 for success.
+ */
 static void
 init_output_kweval(t_topology *top, gmx_ana_selvalue_t *out, void *data);
 /** Frees the data allocated for keyword evaluation in an arbitrary group. */
@@ -239,8 +365,7 @@ static void
 init_frame_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data);
 /** Evaluates keywords in an arbitrary group. */
 static void
-evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
+evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, gmx_ana_index_t * /* g */, gmx_ana_selvalue_t *out, void *data);
 
 /*! \internal \brief
  * Data structure for keyword evaluation in arbitrary groups.
@@ -265,15 +390,8 @@ static gmx_ana_selparam_t smparams_kweval[] = {
  * INTEGER KEYWORD EVALUATION
  ********************************************************************/
 
-/*!
- * \param[in] npar  Not used.
- * \param     param Not used.
- * \returns   Pointer to the allocated data (\ref t_methoddata_kwint).
- *
- * Allocates memory for a \ref t_methoddata_kwint structure.
- */
 static void *
-init_data_kwint(int npar, gmx_ana_selparam_t *param)
+init_data_kwint(int  /* npar */, gmx_ana_selparam_t * /* param */)
 {
     t_methoddata_kwint *data;
 
@@ -281,14 +399,8 @@ init_data_kwint(int npar, gmx_ana_selparam_t *param)
     return data;
 }
 
-/*!
- * \param[in] top   Not used.
- * \param[in] npar  Not used (should be 2).
- * \param[in] param Method parameters (should point to \ref smparams_keyword_int).
- * \param[in] data  Should point to \ref t_methoddata_kwint.
- */
 static void
-init_kwint(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
+init_kwint(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
 {
     t_methoddata_kwint *d = (t_methoddata_kwint *)data;
 
@@ -306,7 +418,7 @@ init_kwint(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
  * Matching atoms are stored in \p out->u.g.
  */
 static void
-evaluate_keyword_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_keyword_int(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_kwint *d = (t_methoddata_kwint *)data;
@@ -314,7 +426,7 @@ evaluate_keyword_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
     int                 val;
 
     out->u.g->isize = 0;
-    n    = d->n;
+    n               = d->n;
     for (i = 0; i < g->isize; ++i)
     {
         val = d->v[i];
@@ -353,15 +465,8 @@ evaluate_keyword_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
  * REAL KEYWORD EVALUATION
  ********************************************************************/
 
-/*!
- * \param[in] npar  Not used.
- * \param     param Not used.
- * \returns   Pointer to the allocated data (\ref t_methoddata_kwreal).
- *
- * Allocates memory for a \ref t_methoddata_kwreal structure.
- */
 static void *
-init_data_kwreal(int npar, gmx_ana_selparam_t *param)
+init_data_kwreal(int /* npar */, gmx_ana_selparam_t * /* param */)
 {
     t_methoddata_kwreal *data;
 
@@ -369,15 +474,8 @@ init_data_kwreal(int npar, gmx_ana_selparam_t *param)
     return data;
 }
 
-/*!
- * \param[in] top   Not used.
- * \param[in] npar  Not used (should be 2).
- * \param[in] param Method parameters (should point to \ref smparams_keyword_real).
- * \param[in] data  Should point to \ref t_methoddata_kwreal.
- * \returns   0 (the initialization always succeeds).
- */
 static void
-init_kwreal(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
+init_kwreal(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
 {
     t_methoddata_kwreal *d = (t_methoddata_kwreal *)data;
 
@@ -395,15 +493,15 @@ init_kwreal(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
  * Matching atoms are stored in \p out->u.g.
  */
 static void
-evaluate_keyword_real(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                     gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+evaluate_keyword_real(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
+                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_kwreal *d = (t_methoddata_kwreal *)data;
     int                  n, i, j, jmin, jmax;
     real                 val;
 
     out->u.g->isize = 0;
-    n    = d->n;
+    n               = d->n;
     for (i = 0; i < g->isize; ++i)
     {
         val = d->v[i];
@@ -442,108 +540,62 @@ evaluate_keyword_real(t_topology *top, t_trxframe *fr, t_pbc *pbc,
  * STRING KEYWORD EVALUATION
  ********************************************************************/
 
-/*!
- * \param[in] npar  Not used.
- * \param     param Not used.
- * \returns Pointer to the allocated data (\ref t_methoddata_kwstr).
- *
- * Allocates memory for a \ref t_methoddata_kwstr structure.
- */
 static void *
-init_data_kwstr(int npar, gmx_ana_selparam_t *param)
+init_data_kwstr(int /* npar */, gmx_ana_selparam_t * /* param */)
 {
-    t_methoddata_kwstr *data;
-
-    snew(data, 1);
+    t_methoddata_kwstr *data = new t_methoddata_kwstr();
+    data->matchType = gmx::eStringMatchType_Auto;
     return data;
 }
 
 /*!
- * \param[in] top   Not used.
- * \param[in] npar  Not used (should be 2).
- * \param[in] param Method parameters (should point to \ref smparams_keyword_str).
- * \param[in] data  Should point to \ref t_methoddata_kwstr.
+ * \param[in,out] sel   Selection element to initialize.
+ * \param[in]     matchType  Method to use to match string values.
+ *
+ * Sets the string matching method for string keyword matching.
  */
+void
+_gmx_selelem_set_kwstr_match_type(const gmx::SelectionTreeElementPointer &sel,
+                                  gmx::SelectionStringMatchType           matchType)
+{
+    t_methoddata_kwstr *d = static_cast<t_methoddata_kwstr *>(sel->u.expr.mdata);
+
+    if (sel->type != SEL_EXPRESSION || !sel->u.expr.method
+        || sel->u.expr.method->name != sm_keyword_str.name)
+    {
+        return;
+    }
+    d->matchType = matchType;
+}
+
 static void
-init_kwstr(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
+init_kwstr(t_topology * /* top */, int /* npar */, gmx_ana_selparam_t *param, void *data)
 {
-    t_methoddata_kwstr *d = (t_methoddata_kwstr *)data;
-    char               *s;
-    int                 i;
-    size_t              j;
-    bool                bRegExp;
+    t_methoddata_kwstr *d = static_cast<t_methoddata_kwstr *>(data);
 
     d->v   = param[0].val.u.s;
-    d->n   = param[1].val.nr;
     /* Return if this is not the first time */
-    if (d->m)
+    if (!d->matches.empty())
     {
         return;
     }
-    snew(d->m, d->n);
-    for (i = 0; i < d->n; ++i)
+    int n = param[1].val.nr;
+    d->matches.reserve(n);
+    for (int i = 0; i < n; ++i)
     {
-        s = param[1].val.u.s[i];
-        bRegExp = false;
-        for (j = 0; j < strlen(s); ++j)
-        {
-            if (ispunct(s[j]) && s[j] != '?' && s[j] != '*')
-            {
-                bRegExp = true;
-                break;
-            }
-        }
-        if (bRegExp)
-        {
-            // TODO: Get rid of these prints to stderr
-#ifdef USE_REGEX
-            char               *buf;
-            snew(buf, strlen(s) + 3);
-            sprintf(buf, "^%s$", s);
-            if (regcomp(&d->m[i].u.r, buf, REG_EXTENDED | REG_NOSUB))
-            {
-                bRegExp = false;
-                fprintf(stderr, "WARNING: error in regular expression,\n"
-                                "         will match '%s' as a simple string\n", s);
-            }
-            sfree(buf);
-#else
-            bRegExp = false;
-            fprintf(stderr, "WARNING: no regular expressions support,\n"
-                            "         will match '%s' as a simple string\n", s);
-#endif
-        }
-        if (!bRegExp)
-        {
-            d->m[i].u.s = s;
-        }
-        d->m[i].bRegExp = bRegExp;
+        const char *s = param[1].val.u.s[i];
+        d->matches.push_back(StringKeywordMatchItem(d->matchType, s));
     }
 }
 
 /*!
- * \param data Data to free (should point to a \ref t_methoddata_kwstr).
- *
- * Frees the memory allocated for t_methoddata_kwstr::val.
+ * \param data Data to free (should point to a t_methoddata_kwstr).
  */
 static void
 free_data_kwstr(void *data)
 {
-    t_methoddata_kwstr *d = (t_methoddata_kwstr *)data;
-    int                 i;
-
-    for (i = 0; i < d->n; ++i)
-    {
-        if (d->m[i].bRegExp)
-        {
-#ifdef USE_REGEX
-            /* This branch should only be taken if regular expressions
-             * are available, but the ifdef is still needed. */
-            regfree(&d->m[i].u.r);
-#endif
-        }
-    }
-    sfree(d->m);
+    t_methoddata_kwstr *d = static_cast<t_methoddata_kwstr *>(data);
+    delete d;
 }
 
 /*!
@@ -556,42 +608,22 @@ free_data_kwstr(void *data)
  * Matching atoms are stored in \p out->u.g.
  */
 static void
-evaluate_keyword_str(t_topology *top, t_trxframe *fr, t_pbc *pbc,
+evaluate_keyword_str(t_topology * /* top */, t_trxframe * /* fr */, t_pbc * /* pbc */,
                      gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
 {
-    t_methoddata_kwstr *d = (t_methoddata_kwstr *)data;
-    int                 i, j;
-    bool                bFound;
+    t_methoddata_kwstr *d = static_cast<t_methoddata_kwstr *>(data);
 
     out->u.g->isize = 0;
-    for (i = 0; i < g->isize; ++i)
+    for (int i = 0; i < g->isize; ++i)
     {
-        bFound = false;
-        for (j = 0; j < d->n && !bFound; ++j)
+        for (size_t j = 0; j < d->matches.size(); ++j)
         {
-            if (d->m[j].bRegExp)
-            {
-#ifdef USE_REGEX
-                /* This branch should only be taken if regular expressions
-                 * are available, but the ifdef is still needed. */
-                if (!regexec(&d->m[j].u.r, d->v[i], 0, NULL, 0))
-                {
-                    bFound = true;
-                }
-#endif
-            }
-            else
+            if (d->matches[j].match(d->matchType, d->v[i]))
             {
-                if (gmx_wcmatch(d->m[j].u.s, d->v[i]) == 0)
-                {
-                    bFound = true;
-                }
+                out->u.g->index[out->u.g->isize++] = g->index[i];
+                break;
             }
         }
-        if (bFound)
-        {
-            out->u.g->index[out->u.g->isize++] = g->index[i];
-        }
     }
 }
 
@@ -600,35 +632,21 @@ evaluate_keyword_str(t_topology *top, t_trxframe *fr, t_pbc *pbc,
  * KEYWORD EVALUATION FOR ARBITRARY GROUPS
  ********************************************************************/
 
-/*!
- * \param[in] top   Not used.
- * \param[in] npar  Not used.
- * \param[in] param Not used.
- * \param[in] data  Should point to \ref t_methoddata_kweval.
- * \returns   0 on success, a non-zero error code on return.
- *
- * Calls the initialization method of the wrapped keyword.
- */
 static void
-init_kweval(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
+init_kweval(t_topology *top, int /* npar */, gmx_ana_selparam_t * /* param */, void *data)
 {
     t_methoddata_kweval *d = (t_methoddata_kweval *)data;
 
     d->kwmethod->init(top, 0, NULL, d->kwmdata);
 }
 
-/*!
- * \param[in]     top   Not used.
- * \param[in,out] out   Pointer to output data structure.
- * \param[in,out] data  Should point to \c t_methoddata_kweval.
- * \returns       0 for success.
- */
 static void
-init_output_kweval(t_topology *top, gmx_ana_selvalue_t *out, void *data)
+init_output_kweval(t_topology * /* top */, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_kweval *d = (t_methoddata_kweval *)data;
 
     out->nr = d->g.isize;
+    _gmx_selvalue_reserve(out, out->nr);
 }
 
 /*!
@@ -642,6 +660,7 @@ free_data_kweval(void *data)
     t_methoddata_kweval *d = (t_methoddata_kweval *)data;
 
     _gmx_selelem_free_method(d->kwmethod, d->kwmdata);
+    sfree(d);
 }
 
 /*!
@@ -672,7 +691,7 @@ init_frame_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc, void *data)
  */
 static void
 evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc,
-                gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
+                gmx_ana_index_t * /* g */, gmx_ana_selvalue_t *out, void *data)
 {
     t_methoddata_kweval *d = (t_methoddata_kweval *)data;
 
@@ -680,24 +699,21 @@ evaluate_kweval(t_topology *top, t_trxframe *fr, t_pbc *pbc,
 }
 
 /*!
- * \param[out]  selp    Pointer to receive a pointer to the created selection
- *      element (set to NULL on error).
  * \param[in]   method  Keyword selection method to evaluate.
- * \param[in]   param   Parameter that gives the group to evaluate \p method in.
+ * \param[in]   params  Parameter that gives the group to evaluate \p method in.
  * \param[in]   scanner Scanner data structure.
- * \returns     0 on success, non-zero error code on error.
+ * \returns     Pointer to the created selection element (NULL on error).
+ *
+ * Creates a \ref SEL_EXPRESSION selection element that evaluates the keyword
+ * method given by \p method in the group given by \p param.
  *
- * Creates a \ref SEL_EXPRESSION selection element (pointer put in \c *selp)
- * that evaluates the keyword method given by \p method in the group given by
- * \p param.
+ * The name of \p param should be empty.
  */
-int
-_gmx_sel_init_keyword_evaluator(t_selelem **selp, gmx_ana_selmethod_t *method,
-                                t_selexpr_param *param, void *scanner)
+gmx::SelectionTreeElementPointer
+_gmx_sel_init_keyword_evaluator(gmx_ana_selmethod_t                     *method,
+                                const gmx::SelectionParserParameterList &params,
+                                void                                    *scanner)
 {
-    t_selelem            *sel;
-    t_methoddata_kweval  *data;
-
     gmx::MessageStringCollector *errors = _gmx_sel_lexer_error_reporter(scanner);
     char  buf[1024];
     sprintf(buf, "In evaluation of '%s'", method->name);
@@ -706,15 +722,15 @@ _gmx_sel_init_keyword_evaluator(t_selelem **selp, gmx_ana_selmethod_t *method,
     if ((method->flags & (SMETH_SINGLEVAL | SMETH_VARNUMVAL))
         || method->outinit || method->pupdate)
     {
-        _gmx_selexpr_free_params(param);
-        GMX_ERROR(gmx::eeInternalError,
-                  "Unsupported keyword method for arbitrary group evaluation");
+        GMX_THROW(gmx::InternalError(
+                          "Unsupported keyword method for arbitrary group evaluation"));
     }
 
-    *selp = NULL;
-    sel = _gmx_selelem_create(SEL_EXPRESSION);
+    gmx::SelectionTreeElementPointer sel(
+            new gmx::SelectionTreeElement(SEL_EXPRESSION));
     _gmx_selelem_set_method(sel, method, scanner);
 
+    t_methoddata_kweval  *data;
     snew(data, 1);
     data->kwmethod = sel->u.expr.method;
     data->kwmdata  = sel->u.expr.mdata;
@@ -738,14 +754,10 @@ _gmx_sel_init_keyword_evaluator(t_selelem **selp, gmx_ana_selmethod_t *method,
 
     sel->u.expr.method->param[0].val.u.g = &data->g;
 
-    sfree(param->name);
-    param->name = NULL;
-    if (!_gmx_sel_parse_params(param, sel->u.expr.method->nparams,
+    if (!_gmx_sel_parse_params(params, sel->u.expr.method->nparams,
                                sel->u.expr.method->param, sel, scanner))
     {
-        _gmx_selelem_free(sel);
-        return -1;
+        return gmx::SelectionTreeElementPointer();
     }
-    *selp = sel;
-    return 0;
+    return sel;
 }