summaryrefslogtreecommitdiff
path: root/src/bin/eolian_cxx
diff options
context:
space:
mode:
authorSavio Sena <savio@expertisesolutions.com.br>2014-05-03 00:55:51 +0200
committerCedric Bail <cedric.bail@free.fr>2014-05-03 00:56:32 +0200
commit46b6e8a563bd429690e7bffba4e98d06aa40798d (patch)
treeb7a2aebfc32bcc6d7a2600072a00d69a9f68d9a1 /src/bin/eolian_cxx
parent64c6c63725d96f03baf34b660ca71e13b29078c1 (diff)
eolian_cxx: initial version of the EFL C++ Bindings Generator.
Summary: This patch adds 'eolian_cxx' -- a C++ bindings generator -- to the EFL tree. Eolian Cxx uses Eolian API to read .eo files and generate .eo.hh. It relies/depends on Eo Cxx and Eina Cxx (both non-generated bindings). src/bin/eolian_cxx: The eolian_cxx program. src/lib/eolian_cxx: A header-only library that implements the C++ code generation that binds the .eo classes. =Examples= src/examples/eolian_cxx/eolian_cxx_simple_01.cc: The simplest example, it just uses some "dummy" generated C++ classes. src/examples/eolian_cxx/eolian_cxx_inherit_01.cc: Illustrates how pure C++ classes inherit from .eo generated classes. src/examples/evas/evas_cxx_rectangle.cc: More realistic example using the generated bindings Evas Cxx. Still a bit shallow because we don't have full fledged .eo descriptions yet, but will be improved. =Important= The generated code is not supported and not a stable API/ABI. It is here to gather people interest and get review before we set things in stone for release 1.11. @feature Reviewers: cedric, smohanty, raster, stefan_schmidt CC: felipealmeida, JackDanielZ, cedric, stefan Differential Revision: https://phab.enlightenment.org/D805 Signed-off-by: Cedric Bail <cedric.bail@free.fr>
Diffstat (limited to 'src/bin/eolian_cxx')
-rw-r--r--src/bin/eolian_cxx/.gitignore1
-rw-r--r--src/bin/eolian_cxx/comments.cc110
-rw-r--r--src/bin/eolian_cxx/comments.hh29
-rw-r--r--src/bin/eolian_cxx/convert.cc304
-rw-r--r--src/bin/eolian_cxx/convert.hh9
-rw-r--r--src/bin/eolian_cxx/eo_read.h62
-rw-r--r--src/bin/eolian_cxx/eolian_cxx.cc337
-rw-r--r--src/bin/eolian_cxx/safe_strings.hh28
8 files changed, 880 insertions, 0 deletions
diff --git a/src/bin/eolian_cxx/.gitignore b/src/bin/eolian_cxx/.gitignore
new file mode 100644
index 0000000000..cfe67763b0
--- /dev/null
+++ b/src/bin/eolian_cxx/.gitignore
@@ -0,0 +1 @@
/eolian_cxx
diff --git a/src/bin/eolian_cxx/comments.cc b/src/bin/eolian_cxx/comments.cc
new file mode 100644
index 0000000000..afe725f300
--- /dev/null
+++ b/src/bin/eolian_cxx/comments.cc
@@ -0,0 +1,110 @@
1
2#include "comments.hh"
3#include "safe_strings.hh"
4
5static std::string
6_comment_parameter(Eolian_Function_Parameter param)
7{
8 Eolian_Parameter_Dir direction;
9 Eina_Stringshare *description;
10
11 eolian_parameter_information_get
12 (param, &direction, NULL, NULL, &description);
13
14 std::string doc = "@param";
15 if (direction == EOLIAN_IN_PARAM) doc += " ";
16 else if (direction == EOLIAN_OUT_PARAM) doc += "[out] ";
17 else if (direction == EOLIAN_INOUT_PARAM) doc += "[inout] ";
18 else assert(false);
19
20 doc += safe_strshare(eolian_parameter_name_get(param));
21 doc += " ";
22 doc += safe_str(description);
23
24 return doc;
25}
26
27static std::string
28_comment_parameters_list(const Eina_List *params)
29{
30 std::string doc = "";
31 const Eina_List *it;
32 void *curr;
33 EINA_LIST_FOREACH (params, it, curr)
34 {
35 doc += _comment_parameter
36 (static_cast<Eolian_Function_Parameter>(curr)) + "\n";
37 }
38 return doc;
39}
40
41static std::string
42_comment_brief_and_params(Eolian_Function function,
43 const char *key = EOLIAN_COMMENT)
44{
45 std::string doc = "";
46 std::string func = safe_str(eolian_function_description_get(function, key));
47 if (func != "")
48 {
49 doc += "@brief " + func + "\n\n";
50 }
51 std::string params = _comment_parameters_list(eolian_parameters_list_get(function));
52 if (params != "")
53 {
54 doc += params + "\n";
55 }
56 return doc;
57}
58
59static std::string
60_comment_return(Eolian_Function function,
61 Eolian_Function_Type rettype)
62{
63 std::string doc = "";
64 std::string ret = safe_str(eolian_function_return_type_get(function, rettype));
65 std::string comment = safe_str(eolian_function_return_comment_get(function, rettype));
66 if (ret != "void" && ret != "" && comment != "")
67 {
68 doc = "@return " + comment;
69 }
70 return doc;
71}
72
73namespace detail {
74
75std::string
76eolian_class_comment(const char *classname)
77{
78 return safe_str(eolian_class_description_get(classname));
79}
80
81std::string
82eolian_constructor_comment(Eolian_Function constructor)
83{
84 return _comment_brief_and_params(constructor);
85}
86
87std::string eolian_function_comment(Eolian_Function function)
88{
89 std::string doc = _comment_brief_and_params(function);
90 doc += _comment_return(function, EOLIAN_METHOD);
91 return doc;
92}
93
94std::string eolian_property_getter_comment(Eolian_Function property)
95{
96 std::string doc = _comment_brief_and_params
97 (property, EOLIAN_COMMENT_GET);
98 doc += _comment_return(property, EOLIAN_PROP_GET);
99 return doc;
100}
101
102std::string eolian_property_setter_comment(Eolian_Function property)
103{
104 std::string doc = _comment_brief_and_params
105 (property, EOLIAN_COMMENT_SET);
106 doc += _comment_return(property, EOLIAN_PROP_SET);
107 return doc;
108}
109
110} // namespace detail
diff --git a/src/bin/eolian_cxx/comments.hh b/src/bin/eolian_cxx/comments.hh
new file mode 100644
index 0000000000..3aaf7562ce
--- /dev/null
+++ b/src/bin/eolian_cxx/comments.hh
@@ -0,0 +1,29 @@
1
2#ifndef EOLIAN_CXX_EOLIAN_CONVERT_COMMENTS_HH
3#define EOLIAN_CXX_EOLIAN_CONVERT_COMMENTS_HH
4
5#include <string>
6
7extern "C"
8{
9#include <Eina.h>
10#include <Eolian.h>
11}
12
13#include <Eolian_Cxx.hh>
14
15namespace detail {
16
17std::string eolian_class_comment(const char *classname);
18
19std::string eolian_constructor_comment(Eolian_Function constructor);
20
21std::string eolian_function_comment(Eolian_Function function);
22
23std::string eolian_property_getter_comment(Eolian_Function function);
24
25std::string eolian_property_setter_comment(Eolian_Function function);
26
27}
28
29#endif // EOLIAN_CXX_EOLIAN_CONVERT_COMMENTS_HH
diff --git a/src/bin/eolian_cxx/convert.cc b/src/bin/eolian_cxx/convert.cc
new file mode 100644
index 0000000000..6672daa54f
--- /dev/null
+++ b/src/bin/eolian_cxx/convert.cc
@@ -0,0 +1,304 @@
1#include <vector>
2#include <algorithm>
3#include <cassert>
4
5#ifdef HAVE_CONFIG_H
6# include <config.h>
7#endif
8
9#include <Eina.h>
10#include <Eina.hh>
11#include <Eo.h>
12#include <Eolian.h>
13
14#include "eo_types.hh"
15#include "safe_strings.hh"
16#include "comments.hh"
17
18static std::string
19_resolve_param_type(Eolian_Function_Parameter id, bool is_get)
20{
21 Eolian_Parameter_Dir dir;
22 const char *type;
23 bool is_const;
24 std::string res;
25
26 eolian_parameter_information_get(id, &dir, &type, NULL, NULL);
27 is_const = eolian_parameter_const_attribute_get(id, is_get);
28 res = safe_str(type);
29 assert(res != "");
30 if (is_const) res = std::string("const ") + res;
31 if (dir == EOLIAN_OUT_PARAM || dir == EOLIAN_INOUT_PARAM) res += "*";
32 return res;
33}
34
35static efl::eolian::parameters_container_type
36_get_params(const Eina_List *eolian_params, bool is_get = false)
37{
38 const Eina_List *it;
39 void *curr;
40 if (eolian_params == NULL)
41 {
42 return efl::eolian::parameters_container_type();
43 }
44 efl::eolian::parameters_container_type list;
45 EINA_LIST_FOREACH (eolian_params, it, curr)
46 {
47 Eolian_Function_Parameter id =
48 (static_cast<Eolian_Function_Parameter>(curr));
49 list.push_back({
50 _resolve_param_type(id, is_get),
51 safe_strshare(eolian_parameter_name_get(id))
52 });
53 }
54 return list;
55}
56
57static efl::eolian::functions_container_type
58_get_properties(const char *classname)
59{
60 efl::eolian::functions_container_type container;
61
62 std::string cxx_classname = classname;
63 std::transform(cxx_classname.begin(), cxx_classname.end(),
64 cxx_classname.begin(), ::tolower);
65
66 const Eina_List *properties;
67 properties = eolian_class_functions_list_get(classname, EOLIAN_PROPERTY);
68
69 const Eina_List *it;
70 void *curr;
71 std::string prefix(safe_str(eolian_class_eo_prefix_get(classname)));
72 EINA_LIST_FOREACH (properties, it, curr)
73 {
74 Eolian_Function property = static_cast<Eolian_Function>(curr);
75 Eolian_Function_Type type = eolian_function_type_get(property);
76 std::string name = safe_str(eolian_function_name_get(property));
77 if (type == EOLIAN_PROP_GET || type == EOLIAN_PROPERTY)
78 {
79 const Eina_List *keys_ = eolian_property_keys_list_get(property);
80 efl::eolian::parameters_container_type params = _get_params
81 (eolian_parameters_list_get(property), true);
82 efl::eolian::eo_function getter;
83 getter.type = efl::eolian::eo_function::regular_;
84 getter.name = name + "_get";
85 getter.impl = (prefix != "" ? prefix : cxx_classname) + "_" + getter.name;
86 std::string ret = safe_str
87 (eolian_function_return_type_get(property, EOLIAN_PROP_GET));
88 if (ret == "") ret = "void";
89
90 // if the getter has a single parameter and void return
91 // we translate it to a getter with no parameters that
92 // returns its type.
93 if ((ret == "void") && params.size() == 1)
94 {
95 getter.ret = params[0].type;
96 getter.params.clear();
97 }
98 else // otherwise just create the described getter
99 {
100 getter.ret = ret;
101 getter.params = params;
102 std::transform
103 (params.begin(), params.end(), getter.params.begin(),
104 [](efl::eolian::eo_parameter const& param)
105 {
106 return efl::eolian::eo_parameter
107 { param.type + "*", param.name };
108 });
109 }
110 if (eina_list_count(keys_) > 0)
111 {
112 efl::eolian::parameters_container_type keys = _get_params(keys_, true);
113 keys.reserve(keys.size() + getter.params.size());
114 keys.insert(keys.end(), getter.params.begin(), getter.params.end());
115 getter.params = keys;
116 }
117 getter.comment = detail::eolian_property_getter_comment(property);
118 container.push_back(getter);
119 }
120 if (type == EOLIAN_PROP_SET || type == EOLIAN_PROPERTY)
121 {
122 const Eina_List *keys_ = eolian_property_keys_list_get(property);
123 const Eina_List *args_ = eolian_parameters_list_get(property);
124 Eina_List *params_ = eina_list_merge(eina_list_clone(keys_), eina_list_clone(args_));
125 efl::eolian::parameters_container_type params = _get_params(params_);
126 eina_list_free(params_);
127 efl::eolian::eo_function setter;
128 setter.type = efl::eolian::eo_function::regular_;
129 setter.name = name + "_set";
130 setter.impl = (prefix != "" ? prefix : cxx_classname) + "_" + setter.name;
131 setter.params = params;
132 setter.ret = safe_str(eolian_function_return_type_get
133 (property, EOLIAN_PROP_SET));
134 if (setter.ret == "") setter.ret = "void";
135 setter.comment = detail::eolian_property_setter_comment(property);
136 container.push_back(setter);
137 }
138 }
139 return container;
140}
141
142namespace detail {
143
144void
145convert_eolian_inheritances(efl::eolian::eo_class& cls, const char *classname)
146{
147 const Eina_List *inheritances = eolian_class_inherits_list_get(classname);
148 const Eina_List *it;
149 void *curr;
150
151 if (eina_list_count(inheritances) == 0
152 || eina_list_data_get(inheritances) == NULL)
153 {
154 cls.parent = "efl::eo::base";
155 return;
156 }
157 else
158 {
159 std::string parent =
160 static_cast<const char*>(eina_list_data_get(inheritances));
161 std::transform(parent.begin(), parent.end(), parent.begin(), ::tolower);
162 // "eo_base" is the Eolian name for EO_BASE_CLASS.
163 cls.parent = (parent == "eo_base" || parent == "") ? "efl::eo::base" : parent;
164 }
165
166 inheritances = eina_list_next(inheritances);
167 EINA_LIST_FOREACH (inheritances, it, curr)
168 {
169 std::string extension = static_cast<const char*>(curr);
170 std::transform
171 (extension.begin(), extension.end(), extension.begin(), ::tolower);
172 cls.extensions.push_back(extension);
173 }
174}
175
176void
177convert_eolian_implements(efl::eolian::eo_class& cls, const char *classname)
178{
179 const Eina_List *it;
180 void *curr;
181 std::string prefix(safe_str(eolian_class_eo_prefix_get(classname)));
182 const Eina_List *implements = eolian_class_implements_list_get(classname);
183 Eolian_Implement impl_desc;
184 void *impl_desc_;
185 EINA_LIST_FOREACH(eolian_class_implements_list_get(classname), it, impl_desc_)
186 {
187 Eolian_Implement impl_desc = static_cast<Eolian_Implement>(impl_desc_);
188 Eolian_Function_Type func_type;
189 const char *func_name;
190 const char *impl_class;
191 eolian_implement_information_get
192 (impl_desc, &impl_class, &func_name, &func_type);
193#if 1 // XXX only due to a bug in Eolian we have to double-check
194 if(func_type == EOLIAN_UNRESOLVED &&
195 eolian_class_function_find_by_name(impl_class, func_name, EOLIAN_CTOR) != NULL)
196 func_type = EOLIAN_CTOR;
197#endif
198 if (func_type == EOLIAN_CTOR)
199 {
200 efl::eolian::eo_constructor constructor;
201 Eolian_Function eolian_constructor = eolian_class_function_find_by_name
202 (impl_class, func_name, func_type);
203 assert(eolian_constructor != NULL);
204 std::string parent = safe_str(impl_class);
205 if(parent == "Eo_Base") parent = "eo";
206 else std::transform(parent.begin(), parent.end(), parent.begin(), ::tolower);
207 constructor.name = parent + "_" + safe_str(func_name);
208 constructor.params = _get_params
209 (eolian_parameters_list_get(eolian_constructor));
210 constructor.comment = detail::eolian_constructor_comment
211 (eolian_constructor);
212 cls.constructors.push_back(constructor);
213 }
214 }
215}
216
217void
218convert_eolian_constructors(efl::eolian::eo_class& cls, const char *classname)
219{
220 const Eina_List *it;
221 void *curr;
222 std::string prefix(safe_str(eolian_class_eo_prefix_get(classname)));
223 const Eina_List *constructors =
224 eolian_class_functions_list_get(classname, EOLIAN_CTOR);
225 EINA_LIST_FOREACH (constructors, it, curr)
226 {
227 Eolian_Function eolian_constructor = static_cast<Eolian_Function>(curr);
228 efl::eolian::eo_constructor constructor;
229 constructor.name = (prefix != "" ? prefix : cls.name) + "_" + safe_str
230 (eolian_function_name_get(eolian_constructor));
231 constructor.params = _get_params
232 (eolian_parameters_list_get(eolian_constructor));
233 constructor.comment = detail::eolian_constructor_comment
234 (eolian_constructor);
235 cls.constructors.push_back(constructor);
236 }
237}
238
239void
240convert_eolian_functions(efl::eolian::eo_class& cls, const char *classname)
241{
242 const Eina_List *it;
243 void *curr;
244
245 const Eina_List *eolian_functions =
246 eolian_class_functions_list_get(classname, EOLIAN_METHOD);
247 EINA_LIST_FOREACH (eolian_functions, it, curr)
248 {
249 efl::eolian::eo_function function;
250 Eolian_Function eolian_function = static_cast<Eolian_Function>(curr);
251 std::string prefix(safe_str(eolian_class_eo_prefix_get(classname)));
252 // XXX Eolian only provides regular methods so far
253 function.type = efl::eolian::eo_function::regular_;
254 function.name = safe_str(eolian_function_name_get(eolian_function));
255 function.impl = ( prefix != "" ? prefix : cls.name ) + "_" + function.name;
256 function.ret = safe_str(eolian_function_return_type_get
257 (eolian_function, EOLIAN_METHOD));
258 if(function.ret == "") function.ret = "void";
259 function.params = _get_params(eolian_parameters_list_get(eolian_function));
260 function.comment = detail::eolian_function_comment(eolian_function);
261 cls.functions.push_back(function);
262 }
263}
264
265void
266convert_eolian_properties(efl::eolian::eo_class& cls, const char *classname)
267{
268 efl::eolian::functions_container_type properties = _get_properties(classname);
269 cls.functions.insert(cls.functions.end(), properties.begin(), properties.end());
270}
271
272} // namespace detail {
273
274efl::eolian::eo_class
275_cxx_new(const char *classname)
276{
277 using namespace efl::eolian;
278 eo_class cls;
279 Eolian_Class_Type cls_type = ::eolian_class_type_get(classname);
280 if (cls_type == EOLIAN_CLASS_REGULAR) cls.type = eo_class::regular_;
281 else if (cls_type == EOLIAN_CLASS_ABSTRACT) cls.type = eo_class::regular_noninst_;
282 else if (cls_type == EOLIAN_CLASS_MIXIN) cls.type = eo_class::mixin_;
283 else if (cls_type == EOLIAN_CLASS_INTERFACE) cls.type = eo_class::interface_;
284 else { assert(false); }
285 std::string prefix(safe_str(eolian_class_eo_prefix_get(classname)));
286 cls.name = classname;
287 cls.eo_name = (prefix != "" ? prefix : cls.name) + "_CLASS";
288 cls.comment = detail::eolian_class_comment(classname);
289 std::transform(cls.name.begin(), cls.name.end(), cls.name.begin(), ::tolower);
290 std::transform(cls.eo_name.begin(), cls.eo_name.end(), cls.eo_name.begin(), ::toupper);
291 return cls;
292}
293
294efl::eolian::eo_class
295c_to_cxx(const char *classname)
296{
297 efl::eolian::eo_class cls(_cxx_new(classname));
298 detail::convert_eolian_inheritances(cls, classname);
299 detail::convert_eolian_implements(cls, classname);
300 detail::convert_eolian_constructors(cls, classname);
301 detail::convert_eolian_functions(cls, classname);
302 detail::convert_eolian_properties(cls, classname);
303 return cls;
304}
diff --git a/src/bin/eolian_cxx/convert.hh b/src/bin/eolian_cxx/convert.hh
new file mode 100644
index 0000000000..910d3a5dd8
--- /dev/null
+++ b/src/bin/eolian_cxx/convert.hh
@@ -0,0 +1,9 @@
1
2#ifndef EOLIAN_CXX_EOLIAN_CONVERT_CLASSES_HH
3#define EOLIAN_CXX_EOLIAN_CONVERT_CLASSES_HH
4
5#include "eo_types.hh"
6
7efl::eolian::eo_class c_to_cxx(const char *classname);
8
9#endif // EOLIAN_CXX_EOLIAN_CONVERT_CLASSES_HH
diff --git a/src/bin/eolian_cxx/eo_read.h b/src/bin/eolian_cxx/eo_read.h
new file mode 100644
index 0000000000..2ad332f410
--- /dev/null
+++ b/src/bin/eolian_cxx/eo_read.h
@@ -0,0 +1,62 @@
1
2#ifndef EOLIAN_CXX_EOLIAN_HELPER_H
3#define EOLIAN_CXX_EOLIAN_HELPER_H
4
5#include <Eina.h>
6#include <Eolian.h>
7#include <assert.h>
8
9#define EO_SUFFIX ".eo"
10
11inline Eina_List*
12_list_dir(const char *dir, const char *suffix, Eina_Bool recurse)
13{
14 Eina_List *files = NULL;
15 Eina_Iterator *ls;
16 Eina_File_Direct_Info *info;
17
18 ls = eina_file_direct_ls(dir);
19 if(ls == NULL) return NULL;
20
21 EINA_ITERATOR_FOREACH (ls, info)
22 {
23 assert(info && info->path);
24 if (info->type == EINA_FILE_DIR && recurse)
25 {
26 files = eina_list_merge
27 (files, _list_dir(info->path, suffix, recurse));
28 }
29 else if (eina_str_has_suffix(&info->path[info->name_start], suffix))
30 {
31 files = eina_list_append(files, strdup(info->path));
32 }
33 }
34 eina_iterator_free(ls);
35 return eina_list_sort
36 (files, eina_list_count(files), EINA_COMPARE_CB(strcoll));
37}
38
39inline Eina_List*
40eolian_read_from_fs(const char *path, Eina_Bool recurse)
41{
42 if (eina_str_has_suffix(path, EO_SUFFIX))
43 {
44 if(!eolian_eo_file_parse(path))
45 {
46 /* XXX: fprintf? */
47 fprintf(stderr, "Couldn't load input file: %s\n", path);
48 return NULL;
49 }
50 }
51 else
52 {
53 if (!eolian_directory_scan(path))
54 {
55 /* XXX: fprintf? */
56 fprintf(stderr, "Error scanning directory: %s\n", path);
57 }
58 }
59 return eina_list_clone(eolian_class_names_list_get());
60}
61
62#endif /* EOLIAN_CXX_EOLIAN_HELPER_H */
diff --git a/src/bin/eolian_cxx/eolian_cxx.cc b/src/bin/eolian_cxx/eolian_cxx.cc
new file mode 100644
index 0000000000..c6d146205f
--- /dev/null
+++ b/src/bin/eolian_cxx/eolian_cxx.cc
@@ -0,0 +1,337 @@
1
2#include <iostream>
3#include <fstream>
4
5#include <stdlib.h>
6#include <unistd.h>
7#include <getopt.h>
8
9#include <string>
10#include <algorithm>
11#include <stdexcept>
12#include <iosfwd>
13#include <type_traits>
14#include <cassert>
15
16extern "C"
17{
18#ifdef HAVE_CONFIG_H
19# include <config.h>
20#endif
21
22#include <Eina.h>
23#include <Eo.h>
24#include <Eolian.h>
25}
26
27#include <Eina.hh>
28#include <Eolian_Cxx.hh>
29
30#include "eo_read.h"
31#include "convert.hh"
32#include "safe_strings.hh"
33
34namespace {
35
36// Program options.
37struct options_type
38{
39 std::vector<std::string> in_srcs;
40 std::string out_file;
41 std::string out_dir;
42 std::string classname;
43 std::string name_space;
44 bool recurse;
45 bool generate_all;
46
47 options_type()
48 : in_srcs()
49 , out_file("")
50 , out_dir("")
51 , classname("")
52 , name_space("")
53 , recurse(false)
54 , generate_all(false)
55 {}
56};
57
58efl::eina::log_domain domain("eolian_cxx");
59
60}
61
62static void
63_opt_error(std::string message)
64{
65 EINA_CXX_DOM_LOG_ERR(::domain) << message << std::endl;
66 exit(EXIT_FAILURE);
67}
68
69static void
70_assert_not_dup(std::string option, std::string value)
71{
72 if (value != "")
73 {
74 _opt_error("Option -" + option + " already set (" + value + ")");
75 }
76}
77
78// Try to guess classname from input filenames.
79// Precondition: Input sources must be loaded into Eolian Database
80// otherwise we can't infer the classname from the .eo files.
81// Precondition: Input options must have opts.classname == "".
82static std::string
83_guess_classname_from_sources(::options_type& opts)
84{
85 for (auto filename : opts.in_srcs)
86 {
87 if (const char *cls = eolian_class_find_by_file(filename.c_str()))
88 {
89 return cls;
90 }
91 }
92 return "";
93}
94
95efl::eolian::eo_generator_options
96_resolve_includes(std::string const& classname, ::options_type const& opts)
97{
98 efl::eolian::eo_generator_options gen_opts;
99
100 std::string cls_name = classname;
101 std::transform(cls_name.begin(), cls_name.end(), cls_name.begin(), ::tolower);
102
103 std::string eo_file = safe_str(eolian_class_file_get(classname.c_str()));
104 const size_t last = eo_file.rfind("/");
105 if (last != std::string::npos) eo_file.erase(0, last+1);
106 gen_opts.c_headers.push_back(eo_file + ".h");
107
108 void *cur = NULL;
109 const Eina_List *itr, *inheritances = eolian_class_inherits_list_get(classname.c_str());
110 EINA_LIST_FOREACH(inheritances, itr, cur)
111 {
112 const char *ext = static_cast<const char*>(cur);
113 std::string eo_parent_file = safe_str(eolian_class_file_get(ext));
114 if (!eo_parent_file.empty())
115 {
116 const size_t last = eo_parent_file.rfind("/");
117 if (last != std::string::npos) eo_parent_file.erase(0, last+1);
118 if (eo_parent_file != "eo_base.eo") // we have our own eo_base.hh
119 {
120 gen_opts.cxx_headers.push_back(eo_parent_file + ".hh");
121 }
122 }
123 else
124 {
125 EINA_CXX_DOM_LOG_WARN(::domain)
126 << "Couldn't find source file for class '" << ext << "'";
127 }
128 }
129 return gen_opts;
130}
131
132static void
133_generate(const std::string classname, ::options_type const& opts)
134{
135 efl::eolian::eo_class cls = ::c_to_cxx(classname.c_str());
136 cls.name_space = opts.name_space;
137 efl::eolian::eo_class_validate(cls);
138 efl::eolian::eo_generator_options gen_opts = _resolve_includes(classname, opts);
139 std::string outname = (opts.out_file == "") ? (cls.name + ".eo.hh") : opts.out_file;
140
141 if (opts.out_dir != "")
142 {
143 outname = opts.out_dir + "/" + outname;
144 }
145 if(opts.out_file == "-")
146 {
147 efl::eolian::generate(std::cout, cls, gen_opts);
148 }
149 else
150 {
151 std::ofstream outfile;
152 outfile.open(outname);
153 assert(outfile.good());
154 efl::eolian::generate(outfile, cls, gen_opts);
155 outfile.close();
156 }
157}
158
159static void
160_run(options_type const& opts)
161{
162 if (opts.classname != "")
163 {
164 _generate(opts.classname.c_str(), opts);
165 }
166 else
167 {
168 efl::eina::range_ptr_list<const char* const>
169 classes(eolian_class_names_list_get());
170 for (auto cls : classes)
171 {
172 if (opts.classname == "" || opts.classname == cls)
173 {
174 _generate(cls, opts);
175 }
176 }
177 }
178}
179
180static void
181_print_version()
182{
183 std::cerr
184 << "Eolian C++ Binding Generator (EFL "
185 << PACKAGE_VERSION << ")" << std::endl;
186}
187
188static void
189_validate_options(::options_type const& opts)
190{
191 if (opts.in_srcs.size() == 0)
192 {
193 _opt_error("You must provide at least one input source (-I). "
194 "Either an .eo file or a directory of .eo files.");
195 }
196 else if (opts.out_file != "" && opts.generate_all)
197 {
198 _opt_error("Options -a and -o can't be used together.");
199 }
200 else if (!opts.generate_all && opts.classname == "")
201 {
202 _opt_error("Neither -a nor -c provided. "
203 "Don't know what to generate.");
204 }
205}
206
207static void
208_resolve_classname(options_type& opts)
209{
210 if (opts.classname == "")
211 {
212 std::string cls = _guess_classname_from_sources(opts);
213 opts.classname = cls;
214 }
215 if (opts.classname == "" && opts.out_file != "")
216 {
217 EINA_CXX_DOM_LOG_ERR(::domain)
218 << "Unknown output class for " << opts.out_file
219 << " : Missing '-c' option?";
220 std::abort();
221 }
222}
223
224static void
225_load_classes(options_type const& opts)
226{
227 for (auto src : opts.in_srcs)
228 {
229 if (eolian_read_from_fs(src.c_str(), opts.recurse) == NULL)
230 {
231 EINA_CXX_DOM_LOG_WARN(::domain)
232 << "Couldn't load eolian file: " << src;
233 }
234 }
235}
236
237static void
238_usage(const char *progname)
239{
240 std::cerr
241 << progname
242 << " [options]" << std::endl
243 << "Options:" << std::endl
244 << " -a, --all Generate bindings for all Eo classes." << std::endl
245 << " -c, --class <name> The Eo class name to generate code for." << std::endl
246 << " -D, --out-dir <dir> Output directory where generated code will be written." << std::endl
247 << " -I, --in <file/dir> The source containing the .eo descriptions." << std::endl
248 << " -o, --out-file <file> The output file name. [default: <classname>.eo.hh]" << std::endl
249 << " -n, --namespace <ns> Wrap generated code in a namespace. [Eg: efl::ecore::file]" << std::endl
250 << " -r, --recurse Recurse input directories loading .eo files." << std::endl
251 << " -v, --version Print the version." << std::endl
252 << " -h, --help Print this help." << std::endl;
253 exit(EXIT_FAILURE);
254}
255
256static ::options_type
257_read_options(int argc, char **argv)
258{
259 ::options_type opts;
260
261 const struct option long_options[] =
262 {
263 { "in", required_argument, 0, 'I' },
264 { "out-dir", required_argument, 0, 'D' },
265 { "out-file", required_argument, 0, 'o' },
266 { "class", required_argument, 0, 'c' },
267 { "namespace", required_argument, 0, 'n' },
268 { "all", no_argument, 0, 'a' },
269 { "recurse", no_argument, 0, 'r' },
270 { "version", no_argument, 0, 'v' },
271 { "help", no_argument, 0, 'h' },
272 { 0, 0, 0, 0 }
273 };
274 const char* options = "I:D:o:c:n:arvh";
275
276 int c, idx;
277 while ( (c = getopt_long(argc, argv, options, long_options, &idx)) != -1)
278 {
279 if (c == 'I')
280 {
281 opts.in_srcs.push_back(optarg);
282 }
283 else if (c == 'D')
284 {
285 _assert_not_dup("D", opts.out_dir);
286 opts.out_dir = optarg;
287 }
288 else if (c == 'o')
289 {
290 _assert_not_dup("o", opts.out_file);
291 opts.out_file = optarg;
292 }
293 else if (c == 'c')
294 {
295 _assert_not_dup("c", opts.classname);
296 opts.classname = optarg;
297 }
298 else if (c == 'n')
299 {
300 _assert_not_dup("n", opts.name_space);
301 opts.name_space = optarg;
302 }
303 else if (c == 'a')
304 {
305 opts.generate_all = true;
306 }
307 else if (c == 'r')
308 {
309 opts.recurse = true;
310 }
311 else if (c == 'h')
312 {
313 _usage(argv[0]);
314 }
315 else if (c == 'v')
316 {
317 _print_version();
318 if (argc == 2) exit(EXIT_SUCCESS);
319 }
320 }
321 return opts;
322}
323
324int main(int argc, char **argv)
325{
326 efl::eina::eina_init eina_init;
327 efl::eolian::eolian_init eolian_init;
328#if DEBUG
329 domain.set_level(efl::eina::log_level::debug);
330#endif
331 options_type opts = _read_options(argc, argv);
332 _load_classes(opts);
333 _resolve_classname(opts);
334 _validate_options(opts);
335 _run(opts);
336 return 0;
337}
diff --git a/src/bin/eolian_cxx/safe_strings.hh b/src/bin/eolian_cxx/safe_strings.hh
new file mode 100644
index 0000000000..61f7f9b58f
--- /dev/null
+++ b/src/bin/eolian_cxx/safe_strings.hh
@@ -0,0 +1,28 @@
1
2#ifndef EOLIAN_CXX_BIN_SAFE_STRINGS_HH
3#define EOLIAN_CXX_BIN_SAFE_STRINGS_HH
4
5#include <string>
6
7extern "C"
8{
9#include <Eina.h>
10}
11
12/// @brief Safely convert an const char* to std::string.
13inline std::string
14safe_str(const char* str)
15{
16 return (str != NULL) ? str : "";
17}
18
19/// @brief Safely convert an Eina_Stringshare to std::string.
20inline std::string
21safe_strshare(Eina_Stringshare* strsh)
22{
23 std::string ret = strsh != NULL ? strsh : "";
24 eina_stringshare_del(strsh);
25 return ret;
26}
27
28#endif // EOLIAN_CXX_BIN_SAFE_STRINGS_HH