2 * @brief Implement OmegaScript $transform function.
4 /* Copyright (C) 2003,2009,2015 Olly Betts
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
23 #include "transform.h"
33 static map
<pair
<string
, int>, pcre
*> re_cache
;
36 get_re(const string
& pattern
, int options
)
38 pair
<string
, int> re_key
= make_pair(pattern
, options
);
39 auto re_it
= re_cache
.find(re_key
);
40 if (re_it
!= re_cache
.end()) {
47 pcre_compile(pattern
.c_str(), options
, &error
, &erroffset
, NULL
);
49 string m
= "$transform failed to compile its regular expression: ";
53 re_cache
.insert(make_pair(re_key
, re
));
58 omegascript_match(string
& value
, const vector
<string
> & args
)
62 if (args
.size() > 2) {
63 const string
&opts
= args
[2];
64 for (string::const_iterator i
= opts
.begin(); i
!= opts
.end(); ++i
) {
67 options
|= PCRE_CASELESS
;
70 options
|= PCRE_MULTILINE
;
73 options
|= PCRE_DOTALL
;
76 options
|= PCRE_EXTENDED
;
79 string m
= "Unknown $match option character: ";
86 pcre
* re
= get_re(args
[0], options
);
87 int matches
= pcre_exec(re
, NULL
, args
[1].data(), args
[1].size(),
95 omegascript_transform(string
& value
, const vector
<string
> & args
)
98 bool replace_all
= false;
100 if (args
.size() > 3) {
101 const string
& opts
= args
[3];
102 for (string::const_iterator i
= opts
.begin(); i
!= opts
.end(); ++i
) {
108 options
|= PCRE_CASELESS
;
111 options
|= PCRE_MULTILINE
;
114 options
|= PCRE_DOTALL
;
117 options
|= PCRE_EXTENDED
;
120 string m
= "Unknown $transform option character: ";
128 pcre
* re
= get_re(args
[0], options
);
131 int matches
= pcre_exec(re
, NULL
, args
[2].data(), args
[2].size(),
132 int(start
), 0, offsets
, 30);
134 // (matches == PCRE_ERROR_NOMATCH) is OK, otherwise this is an
135 // error. FIXME: should we report this rather than ignoring it?
139 // Substitute \1 ... \9, and \\.
140 string::const_iterator i
;
141 value
.append(args
[2], start
, offsets
[0] - start
);
142 for (i
= args
[1].begin(); i
!= args
[1].end(); ++i
) {
149 if (rare(++i
== args
[1].end())) {
150 // Trailing single '\'.
156 if (c
>= '1' && c
<= '9') {
158 // If there aren't that many groupings, expand to nothing.
159 if (c
>= matches
) continue;
162 if (c
!= '\\') value
+= char(c
);
166 int off_c
= offsets
[c
* 2];
167 value
.append(args
[2], off_c
, offsets
[c
* 2 + 1] - off_c
);
170 } while (replace_all
);
171 value
.append(args
[2], start
, string::npos
);