1 //
2 // aegis - project change supervisor
3 // Copyright (C) 1995, 1996, 1999, 2002-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 <libaegis/aer/expr.h>
23 #include <libaegis/aer/func/substr.h>
24 #include <libaegis/aer/value/error.h>
25 #include <libaegis/aer/value/integer.h>
26 #include <libaegis/aer/value/string.h>
27 #include <libaegis/sub.h>
28 
29 
~rpt_func_substr()30 rpt_func_substr::~rpt_func_substr()
31 {
32 }
33 
34 
rpt_func_substr()35 rpt_func_substr::rpt_func_substr()
36 {
37 }
38 
39 
40 rpt_func::pointer
create()41 rpt_func_substr::create()
42 {
43     return pointer(new rpt_func_substr());
44 }
45 
46 
47 const char *
name() const48 rpt_func_substr::name()
49     const
50 {
51     return "substr";
52 }
53 
54 
55 bool
optimizable() const56 rpt_func_substr::optimizable()
57     const
58 {
59     return true;
60 }
61 
62 
63 bool
verify(const rpt_expr::pointer & ep) const64 rpt_func_substr::verify(const rpt_expr::pointer &ep)
65     const
66 {
67     return (ep->get_nchildren() == 3);
68 }
69 
70 
71 rpt_value::pointer
run(const rpt_expr::pointer & ep,size_t,rpt_value::pointer * argv) const72 rpt_func_substr::run(const rpt_expr::pointer &ep, size_t,
73     rpt_value::pointer *argv) const
74 {
75     rpt_value::pointer arg = argv[0];
76     assert(!arg->is_an_error());
77     arg = rpt_value::stringize(arg);
78     rpt_value_string *a1sp = dynamic_cast<rpt_value_string *>(arg.get());
79     if (!a1sp)
80     {
81         sub_context_ty sc;
82         sc.var_set_charstar("Function", "substr");
83         sc.var_set_long("Number", 1);
84         sc.var_set_charstar("Name", argv[0]->name());
85         nstring s
86         (
87             sc.subst_intl
88             (
89                 i18n("$function: argument $number: string value required "
90                     "(was given $name)")
91             )
92         );
93         return rpt_value_error::create(ep->get_pos(), s);
94     }
95     nstring subject(a1sp->query());
96 
97     arg = argv[1];
98     assert(!arg->is_an_error());
99     arg = rpt_value::integerize(arg);
100     rpt_value_integer *a2ip = dynamic_cast<rpt_value_integer *>(arg.get());
101     if (!a2ip)
102     {
103         sub_context_ty sc;
104         sc.var_set_charstar("Function", "substr");
105         sc.var_set_long("Number", 2);
106         sc.var_set_charstar("Name", argv[1]->name());
107         nstring s
108         (
109             sc.subst_intl
110             (
111                 i18n("$function: argument $number: integer value "
112                     "required (was given $name)")
113             )
114         );
115         return rpt_value_error::create(ep->get_pos(), s);
116     }
117     long start = a2ip->query();
118 
119     arg = argv[2];
120     assert(!arg->is_an_error());
121     arg = rpt_value::integerize(arg);
122     rpt_value_integer *a3ip = dynamic_cast<rpt_value_integer *>(arg.get());
123     if (!a3ip)
124     {
125         sub_context_ty sc;
126         sc.var_set_charstar("Function", "substr");
127         sc.var_set_long("Number", 3);
128         sc.var_set_charstar("Name", argv[2]->name());
129         nstring s
130         (
131             sc.subst_intl
132             (
133                 i18n("$function: argument $number: integer value "
134                     "required (was given $name)")
135             )
136         );
137         return rpt_value_error::create(ep->get_pos(), s);
138     }
139     long length = a3ip->query();
140 
141     //
142     // clip the start and end to conform to the string
143     //
144     long end = start + length;
145     if (start < 0)
146         start = 0;
147     if (end < 0)
148         end = 0;
149     if (start > (long)subject.size())
150         start = subject.size();
151     if (end > (long)subject.size())
152         end = subject.size();
153     if (end < start)
154     {
155         start = 0;
156         end = 0;
157     }
158 
159     //
160     // build the result
161     //
162     nstring s(subject.c_str() + start, end - start);
163     return rpt_value_string::create(s);
164 }
165 
166 
167 // vim: set ts=8 sw=4 et :
168