Merge "Encapsulate regexp use in selections."
[alexxy/gromacs.git] / src / gromacs / utility / gmxregex.cpp
1 /*
2  *
3  *                This source code is part of
4  *
5  *                 G   R   O   M   A   C   S
6  *
7  *          GROningen MAchine for Chemical Simulations
8  *
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.
13  *
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.
18  *
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.
25  *
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.
28  *
29  * For more info, check our website at http://www.gromacs.org
30  */
31 /*! \internal \file
32  * \brief
33  * Implements regular expression wrappers.
34  *
35  * \author Teemu Murtola <teemu.murtola@cbr.su.se>
36  * \ingroup module_utility
37  */
38 #include "gmxregex.h"
39
40 #ifdef HAVE_CONFIG_H
41 #include "config.h"
42 #endif
43
44 #if defined(HAVE_REGEX_H)
45 // old Mac needs sys/types.h before regex.h
46 #include <sys/types.h>
47 #include <regex.h>
48 #define USE_POSIX_REGEX
49 #endif
50
51 #include "exceptions.h"
52 #include "stringutil.h"
53
54 namespace gmx
55 {
56
57 // static
58 bool Regex::isSupported()
59 {
60 #if defined(USE_POSIX_REGEX)
61     return true;
62 #else
63     return false;
64 #endif
65 }
66
67 #if defined(USE_POSIX_REGEX)
68 class Regex::Impl
69 {
70     public:
71         explicit Impl(const char *value)
72         {
73             compile(value);
74         }
75         explicit Impl(const std::string &value)
76         {
77             compile(value.c_str());
78         }
79         ~Impl()
80         {
81             regfree(&regex_);
82         }
83
84         bool match(const char *value) const
85         {
86             int rc = regexec(&regex_, value, 0, NULL, 0);
87             if (rc != 0 && rc != REG_NOMATCH)
88             {
89                 // TODO: Handle errors.
90             }
91             return (rc == 0);
92         }
93
94     private:
95         void compile(const char *value)
96         {
97             std::string buf(formatString("^%s$", value));
98             int rc = regcomp(&regex_, buf.c_str(), REG_EXTENDED | REG_NOSUB);
99             if (rc != 0)
100             {
101                 // TODO: Better error messages.
102                 GMX_THROW(InvalidInputError(formatString(
103                                 "Error in regular expression \"%s\"", value)));
104             }
105         }
106
107         regex_t                 regex_;
108 };
109 #else
110 class Regex::Impl
111 {
112     public:
113         explicit Impl(const char * /*value*/)
114         {
115             GMX_THROW(NotImplementedError(
116                         "Gromacs is compiled without regular expression support"));
117         }
118         explicit Impl(const std::string & /*value*/)
119         {
120             GMX_THROW(NotImplementedError(
121                         "Gromacs is compiled without regular expression support"));
122         }
123
124         bool match(const char * /*value*/) const
125         {
126             // Should never be reached.
127             GMX_THROW(NotImplementedError(
128                         "Gromacs is compiled without regular expression support"));
129         }
130 };
131 #endif
132
133 Regex::Regex()
134     : impl_(NULL)
135 {
136 }
137
138 Regex::Regex(const char *value)
139     : impl_(new Impl(value))
140 {
141 }
142
143 Regex::Regex(const std::string &value)
144     : impl_(new Impl(value))
145 {
146 }
147
148 Regex::~Regex()
149 {
150 }
151
152 /*! \cond libapi */
153 bool regexMatch(const char *str, const Regex &regex)
154 {
155     if (regex.impl_.get() == NULL)
156     {
157         return false;
158     }
159     return regex.impl_->match(str);
160 }
161
162 bool regexMatch(const std::string &str, const Regex &regex)
163 {
164     return regexMatch(str.c_str(), regex);
165 }
166 //! \endcond
167
168 } // namespace gmx