1 //
2 // aegis - project change supervisor
3 // Copyright (C) 1998, 1999, 2001, 2002, 2004-2008, 2012 Peter Miller
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published
7 // by the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 //
18
19 #include <common/ac/assert.h>
20
21 #include <common/mem.h>
22 #include <common/regula_expre.h>
23 #include <common/trace.h>
24 #include <libaegis/aer/expr.h>
25 #include <libaegis/aer/func/substitute.h>
26 #include <libaegis/aer/value/error.h>
27 #include <libaegis/aer/value/integer.h>
28 #include <libaegis/aer/value/string.h>
29 #include <libaegis/sub.h>
30
31
~rpt_func_substitute()32 rpt_func_substitute::~rpt_func_substitute()
33 {
34 }
35
36
rpt_func_substitute()37 rpt_func_substitute::rpt_func_substitute()
38 {
39 }
40
41
42 rpt_func::pointer
create()43 rpt_func_substitute::create()
44 {
45 return pointer(new rpt_func_substitute());
46 }
47
48
49 const char *
name() const50 rpt_func_substitute::name()
51 const
52 {
53 return "subst";
54 }
55
56
57 bool
optimizable() const58 rpt_func_substitute::optimizable()
59 const
60 {
61 return true;
62 }
63
64
65 bool
verify(const rpt_expr::pointer & ep) const66 rpt_func_substitute::verify(const rpt_expr::pointer &ep)
67 const
68 {
69 return (ep->get_nchildren() == 3 || ep->get_nchildren() == 4);
70 }
71
72
73 rpt_value::pointer
run(const rpt_expr::pointer & ep,size_t argc,rpt_value::pointer * argv) const74 rpt_func_substitute::run(const rpt_expr::pointer &ep, size_t argc,
75 rpt_value::pointer *argv) const
76 {
77 trace(("rpt_func_substitute::run()\n"));
78 //
79 // Get the match pattern.
80 //
81 rpt_value::pointer arg = argv[0];
82 assert(!arg->is_an_error());
83 arg = rpt_value::stringize(arg);
84 rpt_value_string *s0p = dynamic_cast<rpt_value_string *>(arg.get());
85 if (!s0p)
86 {
87 sub_context_ty sc(__FILE__, __LINE__);
88 sc.var_set_charstar("Function", "subst");
89 sc.var_set_long("Number", 1);
90 sc.var_set_charstar("Name", argv[0]->name());
91 nstring s
92 (
93 sc.subst_intl
94 (
95 i18n("$function: argument $number: string value required "
96 "(was given $name)")
97 )
98 );
99 return rpt_value_error::create(ep->get_pos(), s);
100 }
101 nstring lhs(s0p->query());
102
103 //
104 // Get the replacement pattern.
105 //
106 arg = argv[1];
107 assert(!arg->is_an_error());
108 arg = rpt_value::stringize(arg);
109 rpt_value_string *s1p = dynamic_cast<rpt_value_string *>(arg.get());
110 if (!s1p)
111 {
112 sub_context_ty sc(__FILE__, __LINE__);
113 sc.var_set_charstar("Function", "subst");
114 sc.var_set_long("Number", 2);
115 sc.var_set_charstar("Name", argv[1]->name());
116 nstring s
117 (
118 sc.subst_intl
119 (
120 i18n("$function: argument $number: string value required "
121 "(was given $name)")
122 )
123 );
124 return rpt_value_error::create(ep->get_pos(), s);
125 }
126 nstring rhs(s1p->query());
127
128 //
129 // Get the string to be worked over.
130 //
131 arg = argv[2];
132 assert(!arg->is_an_error());
133 arg = rpt_value::stringize(arg);
134 rpt_value_string *s2p = dynamic_cast<rpt_value_string *>(arg.get());
135 if (!s2p)
136 {
137 sub_context_ty sc(__FILE__, __LINE__);
138 sc.var_set_charstar("Function", "subst");
139 sc.var_set_long("Number", 3);
140 sc.var_set_charstar("Name", argv[2]->name());
141 nstring s
142 (
143 sc.subst_intl
144 (
145 i18n("$function: argument $number: string value required "
146 "(was given $name)")
147 )
148 );
149 return rpt_value_error::create(ep->get_pos(), s);
150 }
151 nstring query_input(s2p->query());
152
153 //
154 // Get the count of how many times to match.
155 //
156 long maximum_matches = 0;
157 if (argc >= 4)
158 {
159 arg = argv[3];
160 assert(!arg->is_an_error());
161 arg = rpt_value::integerize(arg);
162 rpt_value_integer *rip = dynamic_cast<rpt_value_integer *>(arg.get());
163 if (!rip)
164 {
165 sub_context_ty sc(__FILE__, __LINE__);
166 sc.var_set_charstar("Function", "subst");
167 sc.var_set_long("Number", 2);
168 sc.var_set_charstar("Name", argv[3]->name());
169 nstring s
170 (
171 sc.subst_intl
172 (
173 i18n("$function: argument $number: integer value "
174 "required (was given $name)")
175 )
176 );
177 return rpt_value_error::create(ep->get_pos(), s);
178 }
179 maximum_matches = rip->query();
180 }
181
182 //
183 // perform the substitution
184 //
185 regular_expression re(lhs);
186 nstring result;
187 if (!re.match_and_substitute(rhs, query_input, maximum_matches, result))
188 {
189 //
190 // Error... probably the LHS pattern was erroneous, but it could
191 // have been the RHS pattern.
192 //
193 // Return an error result.
194 //
195 sub_context_ty sc(__FILE__, __LINE__);
196 sc.var_set_charstar("Function", "subst");
197 sc.var_set_long("Number", 1);
198 sc.var_set_charstar("MeSsaGe", re.strerror());
199 nstring s(sc.subst_intl(i18n("$function: argument $number: $message")));
200 return rpt_value_error::create(ep->get_pos(), s);
201 }
202
203 //
204 // build the result
205 //
206 trace_nstring(result);
207 return rpt_value_string::create(result);
208 }
209
210
211 // vim: set ts=8 sw=4 et :
212