regExpPosix.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | www.openfoam.com
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8  Copyright (C) 2011-2016 OpenFOAM Foundation
9  Copyright (C) 2018-2021 OpenCFD Ltd.
10 -------------------------------------------------------------------------------
11 License
12  This file is part of OpenFOAM.
13 
14  OpenFOAM is free software: you can redistribute it and/or modify it
15  under the terms of the GNU General Public License as published by
16  the Free Software Foundation, either version 3 of the License, or
17  (at your option) any later version.
18 
19  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
20  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
21  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22  for more details.
23 
24  You should have received a copy of the GNU General Public License
25  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
26 
27 \*---------------------------------------------------------------------------*/
28 
29 #include "regExpPosix.H"
30 #include "SubStrings.H"
31 #include "error.H"
32 
33 // * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34 
36 
37 
38 // * * * * * * * * * * * * * * * Local Functions * * * * * * * * * * * * * * //
39 
40 namespace
41 {
42 
43 // Matched entire length
44 static inline bool fullMatch(const regmatch_t& m, const regoff_t len)
45 {
46  return (m.rm_so == 0 && m.rm_eo == len);
47 }
48 
49 } // End anonymous namespace
50 
51 
52 // * * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * //
53 
54 bool Foam::regExpPosix::set_pattern
55 (
56  const char* pattern,
57  size_t len,
58  bool ignoreCase
59 )
60 {
61  clear(); // Also sets ctrl_ = 0
62 
63  const char* pat = pattern;
64  bool doNegate = false;
65 
66  // Handle known embedded prefixes
67  if (len > 2 && pat[0] == '(' && pat[1] == '?')
68  {
69  pat += 2;
70  len -= 2;
71 
72  for (bool done = false; !done && len; ++pat, --len)
73  {
74  switch (*pat)
75  {
76  case '!':
77  {
78  // Negated (inverted) match
79  doNegate = true;
80  break;
81  }
82  case 'i':
83  {
84  // Ignore-case
85  ignoreCase = true;
86  break;
87  }
88  case ')':
89  {
90  // End of prefix parsing
91  done = true;
92  break;
93  }
94  }
95  }
96  }
97 
98  // Avoid zero-length patterns
99  if (len)
100  {
101  int flags = REG_EXTENDED;
102  if (ignoreCase)
103  {
104  flags |= REG_ICASE;
105  }
106 
107  {
108  preg_ = new regex_t;
109  int err = regcomp(preg_, pat, flags);
110 
111  if (err == 0)
112  {
113  ctrl_ = (doNegate ? ctrlType::NEGATED : ctrlType::NORMAL);
114  return true;
115  }
116  else
117  {
118  char errbuf[200];
119  regerror(err, preg_, errbuf, sizeof(errbuf));
120 
122  << "Failed to compile regular expression '"
123  << pattern << "'\n" << errbuf
124  << exit(FatalError);
125  }
126  }
127  }
128 
129  return false;
130 }
131 
132 
133 // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * //
134 
136 {
137  ctrl_ = 0;
138 
139  if (preg_)
140  {
141  regfree(preg_);
142  delete preg_;
143  preg_ = nullptr;
144  return true;
145  }
146 
147  return false;
148 }
149 
150 
151 std::string::size_type Foam::regExpPosix::find(const std::string& text) const
152 {
153  // Find with negated is probably not very reliable...
154  if (!preg_ || !ctrl_)
155  {
156  // Undefined: never matches
157  return std::string::npos;
158  }
159  else if (text.empty())
160  {
161  if (ctrl_ == ctrlType::NEGATED)
162  {
163  return 0; // No match - pretend it starts at position 0
164  }
165  else
166  {
167  return std::string::npos;
168  }
169  }
170  else
171  {
172  const size_t nmatch = 1;
173  regmatch_t pmatch[1];
174 
175  const bool ok = (regexec(preg_, text.c_str(), nmatch, pmatch, 0) == 0);
176 
177  if (ctrl_ == ctrlType::NEGATED)
178  {
179  if (!ok)
180  {
181  return 0; // No match - claim that is starts at position 0
182  }
183  }
184  else if (ok)
185  {
186  return pmatch[0].rm_so;
187  }
188  }
189 
190  return std::string::npos;
191 }
192 
193 
194 bool Foam::regExpPosix::match(const std::string& text) const
195 {
196  bool ok = false;
197 
198  if (!preg_ || !ctrl_)
199  {
200  // Undefined: never matches
201  return false;
202  }
203 
204  const auto len = text.length();
205 
206  if (len)
207  {
208  const size_t nmatch = 1;
209  regmatch_t pmatch[1];
210 
211  // Verify that the entire string was matched
212  // - [0] is the entire match result
213  ok =
214  (
215  regexec(preg_, text.c_str(), nmatch, pmatch, 0) == 0
216  && fullMatch(pmatch[0], len)
217  );
218  }
219 
220  return (ctrl_ == ctrlType::NEGATED ? !ok : ok);
221 }
222 
223 
225 (
226  const std::string& text,
227  SubStrings<std::string>& matches
228 ) const
229 {
230  matches.clear();
231 
232  // Probably does not make sense for negated pattern...
233  if (negated())
234  {
235  return match(text);
236  }
237 
238  const auto len = text.size();
239  if (preg_ && len)
240  {
241  const size_t nmatch = ngroups() + 1;
242  regmatch_t pmatch[nmatch];
243 
244  // Verify that the entire string was matched
245  // - [0] is the entire match result
246  // - [1..] are the match groups (1..)
247  if
248  (
249  regexec(preg_, text.c_str(), nmatch, pmatch, 0) != 0
250  || !fullMatch(pmatch[0], len)
251  )
252  {
253  return false;
254  }
255 
256  matches.reserve(nmatch);
257 
258  for (size_t matchi = 0; matchi < nmatch; ++matchi)
259  {
260  const auto& mat = pmatch[matchi];
261 
262  if (mat.rm_so != -1 && mat.rm_eo != -1)
263  {
264  matches.append
265  (
266  text.cbegin() + mat.rm_so,
267  text.cbegin() + mat.rm_eo
268  );
269  }
270  else
271  {
272  // This may be misleading...
273  matches.append(text.cbegin(), text.cbegin());
274  }
275  }
276 
277  return true;
278  }
279 
280  return false;
281 }
282 
283 
284 // ************************************************************************* //
Foam::regExpPosix::find
std::string::size_type find(const std::string &text) const
Find position within the text.
Definition: regExpPosix.C:151
Foam::SubStrings
Sub-ranges of a string with a structure similar to std::match_results, but without the underlying reg...
Definition: CStringList.H:63
Foam::SubStrings::append
void append(const typename StringType::const_iterator &b, const typename StringType::const_iterator &e)
Append sub-string defined by begin/end iterators.
Definition: SubStrings.H:92
regExpPosix.H
error.H
size_type
graph_traits< Graph >::vertices_size_type size_type
Definition: SloanRenumber.C:76
Foam::FatalError
error FatalError
Foam::regExpPosix::grammar
static int grammar
Grammar (unused) - for compatibility with Foam::regExpCxx.
Definition: regExpPosix.H:118
Foam::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:130
Foam::stringOps::match
bool match(const UList< wordRe > &patterns, const std::string &text)
Return true if text matches one of the regular expressions.
Definition: stringOps.H:76
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:453
SubStrings.H
Foam::regExpPosix::match
bool match(const std::string &text) const
True if the regex matches the entire text.
Definition: regExpPosix.C:194
Foam::regExpPosix::clear
bool clear()
Clear expression.
Definition: regExpPosix.C:135