Don't use POSIX fnmatch() for pattern matching.
[gromacs/qmmm-gamess-us.git] / src / gmxlib / selection / sm_keywords.c
blob511230badf6639a1db1a3f5d61cd43799c89b4de
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 Implementations of internal selection methods for integer and
33 * string keyword evaluation.
35 #ifdef HAVE_CONFIG_H
36 #include <config.h>
37 #endif
39 #include <ctype.h>
40 #include <regex.h>
42 #include <macros.h>
43 #include <smalloc.h>
44 #include <string2.h>
46 #include <selmethod.h>
48 /** Allocates data for integer keyword evaluation. */
49 static void *
50 init_data_kwint(int npar, gmx_ana_selparam_t *param);
51 /** Allocates data for string keyword evaluation. */
52 static void *
53 init_data_kwstr(int npar, gmx_ana_selparam_t *param);
54 /** Initializes data for integer keyword evaluation. */
55 static int
56 init_kwint(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
57 /** Initializes data for string keyword evaluation. */
58 static int
59 init_kwstr(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data);
60 /** Frees the memory allocated for integer keyword evaluation. */
61 static void
62 free_data_kwint(void *data);
63 /** Frees the memory allocated for string keyword evaluation. */
64 static void
65 free_data_kwstr(void *data);
66 /** Evaluates integer selection keywords. */
67 static int
68 evaluate_keyword_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
69 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
70 /** Evaluates string selection keywords. */
71 static int
72 evaluate_keyword_str(t_topology *top, t_trxframe *fr, t_pbc *pbc,
73 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data);
75 /*! \internal \brief
76 * Data structure for integer keyword expression evaluation.
78 typedef struct t_methoddata_kwint
80 /** Array of values for the keyword. */
81 int *v;
82 /** Number of ranges in the \p r array. */
83 int n;
84 /*! \brief
85 * Array of sorted integer ranges to match against.
87 * Each range is made of two integers, giving the endpoints (inclusive).
88 * This field stores the pointer to the ranges allocated by the
89 * parameter parser; see \ref SPAR_RANGES for more information.
91 int *r;
92 } t_methoddata_kwint;
94 /*! \internal \brief
95 * Data structure for string keyword expression evaluation.
97 typedef struct t_methoddata_kwstr
99 /** Array of values for the keyword. */
100 char **v;
101 /** Number of elements in the \p val array. */
102 int n;
103 /*! \internal \brief
104 * Array of strings/regular expressions to match against.
106 struct t_methoddata_kwstr_match {
107 /** TRUE if the expression is a regular expression, FALSE otherwise. */
108 bool bRegExp;
109 /** The value to match against. */
110 union {
111 /** Compiled regular expression if \p bRegExp is TRUE. */
112 regex_t r;
113 /** The string if \p bRegExp is FALSE; */
114 char *s;
115 } u;
116 } *m;
117 } t_methoddata_kwstr;
119 /** Parameters for integer keyword evaluation. */
120 static gmx_ana_selparam_t smparams_keyword_int[] = {
121 {NULL, {INT_VALUE, -1, {NULL}}, NULL, SPAR_ATOMVAL},
122 {NULL, {INT_VALUE, -1, {NULL}}, NULL, SPAR_RANGES | SPAR_VARNUM},
125 /** Parameters for string keyword evaluation. */
126 static gmx_ana_selparam_t smparams_keyword_str[] = {
127 {NULL, {STR_VALUE, -1, {NULL}}, NULL, SPAR_ATOMVAL},
128 {NULL, {STR_VALUE, -1, {NULL}}, NULL, SPAR_VARNUM},
131 /** \internal Selection method data for integer keyword evaluation. */
132 gmx_ana_selmethod_t sm_keyword_int = {
133 "kw_int", GROUP_VALUE, SMETH_SINGLEVAL,
134 asize(smparams_keyword_int), smparams_keyword_int,
135 &init_data_kwint,
136 NULL,
137 &init_kwint,
138 NULL,
139 &free_data_kwint,
140 NULL,
141 &evaluate_keyword_int,
142 NULL,
143 {NULL, 0, NULL},
146 /** \internal Selection method data for string keyword evaluation. */
147 gmx_ana_selmethod_t sm_keyword_str = {
148 "kw_str", GROUP_VALUE, SMETH_SINGLEVAL,
149 asize(smparams_keyword_str), smparams_keyword_str,
150 &init_data_kwstr,
151 NULL,
152 &init_kwstr,
153 NULL,
154 &free_data_kwstr,
155 NULL,
156 &evaluate_keyword_str,
157 NULL,
158 {NULL, 0, NULL},
162 /********************************************************************
163 * INTEGER KEYWORD EVALUATION
164 ********************************************************************/
167 * \param[in] npar Not used.
168 * \param param Not used.
169 * \returns Pointer to the allocated data (\ref t_methoddata_kwint).
171 * Allocates memory for a \ref t_methoddata_kwint structure.
173 static void *
174 init_data_kwint(int npar, gmx_ana_selparam_t *param)
176 t_methoddata_kwint *data;
178 snew(data, 1);
179 return data;
183 * \param[in] top Not used.
184 * \param[in] npar Not used (should be 2).
185 * \param[in] param Method parameters (should point to \ref smparams_keyword_int).
186 * \param[in] data Should point to \ref t_methoddata_kwint.
187 * \returns 0 (the initialization always succeeds).
189 static int
190 init_kwint(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
192 t_methoddata_kwint *d = (t_methoddata_kwint *)data;
194 d->v = param[0].val.u.i;
195 d->n = param[1].val.nr;
196 d->r = param[1].val.u.i;
197 return 0;
201 * \param data Data to free (should point to a \ref t_methoddata_kwint).
203 * Frees the memory allocated for t_methoddata_kwint::r.
205 static void
206 free_data_kwint(void *data)
208 t_methoddata_kwint *d = (t_methoddata_kwint *)data;
210 sfree(d->v);
211 sfree(d->r);
215 * See sel_updatefunc() for description of the parameters.
216 * \p data should point to a \c t_methoddata_kwint.
218 * Does a binary search to find which atoms match the ranges in the
219 * \c t_methoddata_kwint structure for this selection.
220 * Matching atoms are stored in \p out->u.g.
222 static int
223 evaluate_keyword_int(t_topology *top, t_trxframe *fr, t_pbc *pbc,
224 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
226 t_methoddata_kwint *d = (t_methoddata_kwint *)data;
227 int n, i, j, jmin, jmax;
228 int val;
230 out->u.g->isize = 0;
231 n = d->n;
232 for (i = 0; i < g->isize; ++i)
234 val = d->v[i];
235 if (d->r[0] > val || d->r[2*n-1] < val)
237 continue;
239 jmin = 0;
240 jmax = n;
241 while (jmax - jmin > 1)
243 j = jmin + (jmax - jmin) / 2;
244 if (val < d->r[2*j])
246 jmax = j;
248 else
250 jmin = j;
251 if (val <= d->r[2*j+1])
253 break;
255 /* ++jmin;*/
258 if (val <= d->r[2*jmin+1])
260 out->u.g->index[out->u.g->isize++] = g->index[i];
263 return 0;
267 /********************************************************************
268 * STRING KEYWORD EVALUATION
269 ********************************************************************/
272 * \param[in] npar Not used.
273 * \param param Not used.
274 * \returns Pointer to the allocated data (\ref t_methoddata_kwstr).
276 * Allocates memory for a \ref t_methoddata_kwstr structure.
278 static void *
279 init_data_kwstr(int npar, gmx_ana_selparam_t *param)
281 t_methoddata_kwstr *data;
283 snew(data, 1);
284 return data;
288 * \param[in] top Not used.
289 * \param[in] npar Not used (should be 2).
290 * \param[in] param Method parameters (should point to \ref smparams_keyword_str).
291 * \param[in] data Should point to \ref t_methoddata_kwstr.
292 * \returns 0 (the initialization always succeeds).
294 static int
295 init_kwstr(t_topology *top, int npar, gmx_ana_selparam_t *param, void *data)
297 t_methoddata_kwstr *d = (t_methoddata_kwstr *)data;
298 char *buf;
299 char *s;
300 int i;
301 size_t j;
302 bool bRegExp;
304 d->v = param[0].val.u.s;
305 d->n = param[1].val.nr;
306 /* Return if this is not the first time */
307 if (d->m)
309 return 0;
311 snew(d->m, d->n);
312 for (i = 0; i < d->n; ++i)
314 s = param[1].val.u.s[i];
315 bRegExp = FALSE;
316 for (j = 0; j < strlen(s); ++j)
318 if (ispunct(s[j]) && s[j] != '?' && s[j] != '*')
320 bRegExp = TRUE;
321 break;
324 if (bRegExp)
326 snew(buf, strlen(s) + 3);
327 sprintf(buf, "^%s$", s);
328 if (regcomp(&d->m[i].u.r, buf, REG_EXTENDED | REG_NOSUB))
330 bRegExp = FALSE;
331 fprintf(stderr, "warning: will match '%s' as a simple string\n", s);
333 else
335 sfree(s);
337 sfree(buf);
339 if (!bRegExp)
341 d->m[i].u.s = s;
343 d->m[i].bRegExp = bRegExp;
345 sfree(param[1].val.u.s);
346 return 0;
350 * \param data Data to free (should point to a \ref t_methoddata_kwstr).
352 * Frees the memory allocated for t_methoddata_kwstr::val.
354 static void
355 free_data_kwstr(void *data)
357 t_methoddata_kwstr *d = (t_methoddata_kwstr *)data;
358 int i;
360 sfree(d->v);
361 for (i = 0; i < d->n; ++i)
363 if (d->m[i].bRegExp)
365 regfree(&d->m[i].u.r);
367 else
369 sfree(d->m[i].u.s);
372 sfree(d->m);
376 * See sel_updatefunc() for description of the parameters.
377 * \p data should point to a \c t_methoddata_kwstr.
379 * Does a linear search to find which atoms match the strings in the
380 * \c t_methoddata_kwstr structure for this selection.
381 * Wildcards are allowed in the strings.
382 * Matching atoms are stored in \p out->u.g.
384 static int
385 evaluate_keyword_str(t_topology *top, t_trxframe *fr, t_pbc *pbc,
386 gmx_ana_index_t *g, gmx_ana_selvalue_t *out, void *data)
388 t_methoddata_kwstr *d = (t_methoddata_kwstr *)data;
389 int i, j;
390 bool bFound;
392 out->u.g->isize = 0;
393 for (i = 0; i < g->isize; ++i)
395 bFound = FALSE;
396 for (j = 0; j < d->n && !bFound; ++j)
398 if (d->m[j].bRegExp)
400 if (!regexec(&d->m[j].u.r, d->v[i], 0, NULL, 0))
402 bFound = TRUE;
405 else
407 if (gmx_wcmatch(d->m[j].u.s, d->v[i]) == 0)
409 bFound = TRUE;
413 if (bFound)
415 out->u.g->index[out->u.g->isize++] = g->index[i];
418 return 0;