Line data Source code
1 : #include "class_info.hpp"
2 :
3 : #include "oks/kernel.hpp"
4 : #include "oks/class.hpp"
5 : #include "oks/attribute.hpp"
6 : #include "oks/relationship.hpp"
7 : #include "oks/method.hpp"
8 :
9 : #include <stdlib.h>
10 : #include <ctype.h>
11 :
12 : #include <algorithm>
13 : #include <string>
14 : #include <list>
15 : #include <set>
16 : #include <iostream>
17 :
18 : using namespace dunedaq;
19 : using namespace dunedaq::oksdalgen;
20 :
21 : // declare external functions
22 :
23 : extern std::string alnum_name(const std::string& in);
24 : extern std::string capitalize_name(const std::string& in);
25 : extern void print_description(std::ostream& s, const std::string& text, const char * dx);
26 : extern void print_indented(std::ostream& s, const std::string& text, const char * dx);
27 : extern std::string get_type(oks::OksData::Type oks_type, bool is_cpp);
28 : extern void gen_dump_application(std::ostream& s, std::list<std::string>& class_names, const std::string& cpp_ns_name, const std::string& cpp_hdr_dir, const char * conf_header, const char * conf_name, const char * headres_prologue, const char * main_function_prologue);
29 : extern void write_info_file(std::ostream& s, const std::string& cpp_namespace, const std::string& cpp_header_dir, const std::set<const oks::OksClass *, std::less<const oks::OksClass *> >& class_names);
30 : extern std::string get_full_cpp_class_name(const oks::OksClass * c, const ClassInfo::Map& cl_info, const std::string & cpp_ns_name);
31 : extern std::string get_include_dir(const oks::OksClass * c, const ClassInfo::Map& cl_info, const std::string& cpp_hdr_dir);
32 : // extern const std::string& get_package_name(const oks::OksClass * c, const ClassInfo::Map& cl_info, const std::string& java_p_name);
33 : extern void parse_arguments(int argc, char *argv[], std::list<std::string>& class_names, std::list<std::string>& file_names, std::list<std::string>& include_dirs, std::list<std::string>& user_classes, std::string& cpp_dir_name, std::string& cpp_ns_name, std::string& cpp_hdr_dir, std::string& info_file_name, bool& verbose);
34 : extern bool process_external_class(ClassInfo::Map& cl_info, const oks::OksClass * c, const std::list<std::string>& include_dirs, const std::list<std::string>& user_classes, bool verbose);
35 : extern std::string int2dx(int level);
36 : extern int open_cpp_namespace(std::ostream& s, const std::string& value);
37 : extern void close_cpp_namespace(std::ostream& s, int level);
38 : extern std::string get_method_header_prologue(oks::OksMethodImplementation *);
39 : extern std::string get_method_header_epilogue(oks::OksMethodImplementation *);
40 : extern std::string get_public_section(oks::OksMethodImplementation * mi);
41 : extern std::string get_private_section(oks::OksMethodImplementation * mi);
42 : extern std::string get_member_initializer_list(oks::OksMethodImplementation * mi);
43 : extern std::string get_method_implementation_body(oks::OksMethodImplementation * mi);
44 : extern bool get_add_algo_1(oks::OksMethodImplementation * mi);
45 : extern bool get_add_algo_n(oks::OksMethodImplementation * mi);
46 : extern oks::OksMethodImplementation * find_cpp_method_implementation(const oks::OksMethod * method);
47 :
48 :
49 : /**
50 : * The function has_superclass returns true if 'tested' class
51 : * has class 'c' as a superclass
52 : */
53 :
54 : static bool
55 0 : has_superclass(const oks::OksClass * tested, const oks::OksClass * c)
56 : {
57 0 : if (const oks::OksClass::FList * sclasses = tested->all_super_classes())
58 : {
59 0 : for (const auto& i : *sclasses)
60 : {
61 0 : if (i == c)
62 : {
63 0 : return true;
64 : }
65 : }
66 : }
67 :
68 : return false;
69 : }
70 :
71 : const std::string WHITESPACE = " \n\r\t\f\v";
72 :
73 0 : std::string ltrim(const std::string &s)
74 : {
75 0 : size_t start = s.find_first_not_of(WHITESPACE);
76 0 : return (start == std::string::npos) ? "" : s.substr(start);
77 : }
78 :
79 0 : std::string rtrim(const std::string &s)
80 : {
81 0 : size_t end = s.find_last_not_of(WHITESPACE);
82 0 : return (end == std::string::npos) ? "" : s.substr(0, end + 1);
83 : }
84 :
85 0 : std::string trim(const std::string &s) {
86 0 : return rtrim(ltrim(s));
87 : }
88 :
89 : const std::vector<std::string> cpp_method_virtual_specifiers = {
90 : "virtual",
91 : "override",
92 : "final"
93 : };
94 :
95 : static void
96 0 : gen_header(const oks::OksClass *cl,
97 : std::ostream& cpp_file,
98 : const std::string& cpp_ns_name,
99 : const std::string& cpp_hdr_dir,
100 : const ClassInfo::Map& cl_info)
101 : {
102 0 : const std::string name(alnum_name(cl->get_name()));
103 :
104 :
105 : // get includes for super classes if necessary
106 :
107 0 : if (const std::list<std::string*> * super_list = cl->direct_super_classes())
108 : {
109 0 : cpp_file << " // include files for classes used in inheritance hierarchy\n\n";
110 :
111 0 : for (const auto& i : *super_list)
112 : {
113 0 : oks::OksClass * c = cl->get_kernel()->find_class(*i);
114 0 : cpp_file << "#include \"" << get_include_dir(c, cl_info, cpp_hdr_dir) << ".hpp\"\n";
115 : }
116 : }
117 :
118 0 : cpp_file << std::endl;
119 :
120 :
121 : // generate forward declarations if necessary
122 0 : {
123 : // create set of classes to avoid multiple forward declarations of the same class
124 0 : std::set<oks::OksClass*> rclasses;
125 :
126 : // check direct relationships (c++)
127 0 : if (cl->direct_relationships() && !cl->direct_relationships()->empty())
128 0 : for (const auto &i : *cl->direct_relationships())
129 0 : rclasses.insert(i->get_class_type());
130 :
131 : // check methods
132 0 : if (const std::list<oks::OksMethod*> *mlist = cl->direct_methods())
133 : {
134 0 : for (const auto &i : *mlist)
135 : {
136 0 : if (oks::OksMethodImplementation *mi = find_cpp_method_implementation(i))
137 : {
138 0 : const std::string mp(mi->get_prototype());
139 0 : for (const auto &j : cl->get_kernel()->classes())
140 : {
141 0 : const std::string s(j.second->get_name());
142 0 : std::string::size_type idx = mp.find(s);
143 0 : if (idx != std::string::npos && (idx == 0 || !isalnum(mp[idx - 1])) && !isalnum(mp[idx + s.size()]))
144 0 : rclasses.insert(j.second);
145 0 : }
146 0 : }
147 : }
148 : }
149 :
150 0 : NameSpaceInfo ns_info;
151 :
152 0 : for (const auto &c : rclasses)
153 : {
154 : // check if the class' header is not already included
155 0 : if (has_superclass(cl, c) || cl == c)
156 0 : continue;
157 :
158 0 : ClassInfo::Map::const_iterator idx = cl_info.find(c);
159 0 : ns_info.add((idx != cl_info.end() ? (*idx).second.get_namespace() : cpp_ns_name), alnum_name(c->get_name()));
160 : }
161 :
162 0 : if (!ns_info.empty())
163 : {
164 0 : cpp_file << " // forward declaration for classes used in relationships and algorithms\n\n";
165 0 : ns_info.print(cpp_file, 0);
166 0 : cpp_file << "\n\n";
167 : }
168 0 : }
169 :
170 : // generate methods prologues if necessary
171 :
172 0 : if (const std::list<oks::OksMethod*> *mlist = cl->direct_methods())
173 0 : for (const auto &i : *mlist)
174 0 : if (oks::OksMethodImplementation *mi = find_cpp_method_implementation(i))
175 0 : if (!get_method_header_prologue(mi).empty())
176 : {
177 0 : cpp_file << " // prologue of method " << cl->get_name() << "::" << i->get_name() << "()\n";
178 0 : cpp_file << get_method_header_prologue(mi) << std::endl;
179 : }
180 :
181 :
182 : // open namespace
183 :
184 0 : int ns_level = open_cpp_namespace(cpp_file, cpp_ns_name);
185 0 : std::string ns_dx = int2dx(ns_level);
186 0 : std::string ns_dx2 = ns_dx + " ";
187 :
188 0 : const char * dx = ns_dx.c_str(); // are used for alignment
189 0 : const char * dx2 = ns_dx2.c_str();
190 :
191 :
192 : // generate description
193 :
194 0 : {
195 0 : std::string txt("Declares methods to get and put values of attributes / relationships, to print and to destroy object.\n");
196 :
197 0 : txt +=
198 : "<p>\n"
199 : "The methods can throw several exceptions:\n"
200 : "<ul>\n"
201 : " <li><code>conffwk.NotFoundException</code> - in case of wrong attribute or relationship name (e.g. in case of database schema modification)\n"
202 : " <li><code>conffwk.SystemException</code> - in case of system problems (communication or implementation database failure, schema modification, object destruction, etc.)\n"
203 : "</ul>\n"
204 : "<p>\n"
205 : "In addition the methods modifying database (set value, destroy object) can throw <code>conffwk.NotAllowedException</code> "
206 0 : "exception in case, if there are no write access rights or database is already locked by other process.\n";
207 :
208 0 : if (!cl->get_description().empty())
209 : {
210 0 : txt += "\n<p>\n";
211 0 : txt += cl->get_description();
212 0 : txt += "\n";
213 : }
214 :
215 0 : txt += "@author oksdalgen\n";
216 :
217 0 : cpp_file << std::endl;
218 0 : print_description(cpp_file, cl->get_description(), dx);
219 0 : }
220 :
221 : // generate class declaration itself
222 :
223 0 : cpp_file << dx << "class " << name << " : ";
224 :
225 : // generate inheritance list
226 :
227 0 : if (const std::list<std::string*> * super_list = cl->direct_super_classes())
228 : {
229 0 : for (std::list<std::string*>::const_iterator i = super_list->begin(); i != super_list->end();)
230 : {
231 0 : const oks::OksClass * c = cl->get_kernel()->find_class(**i);
232 0 : cpp_file << "public " << get_full_cpp_class_name(c, cl_info, cpp_ns_name);
233 0 : if (++i != super_list->end())
234 0 : cpp_file << ", ";
235 : }
236 : }
237 : else
238 : {
239 0 : cpp_file << "public virtual dunedaq::conffwk::DalObject";
240 : }
241 :
242 0 : cpp_file << " {\n\n";
243 :
244 : // generate standard methods
245 :
246 0 : cpp_file
247 : << dx << " friend class conffwk::Configuration;\n"
248 : << dx << " friend class conffwk::DalObject;\n"
249 : << dx << " friend class conffwk::DalFactory;\n"
250 : << dx << " friend class conffwk::DalRegistry;\n\n"
251 : << dx << " protected:\n\n"
252 : << dx << " " << name << "(conffwk::DalRegistry& db, const conffwk::ConfigObject& obj) noexcept;\n"
253 : << dx << " virtual ~" << name << "() noexcept;\n"
254 : << dx << " virtual void init(bool init_children);\n\n"
255 : << dx << " public:\n\n"
256 : << dx << " /** The name of the configuration class. */\n\n"
257 : << dx << " static const std::string& s_class_name;\n\n\n"
258 : << dx << " /**\n"
259 : << dx << " * \\brief Print details of the " << name << " object.\n"
260 : << dx << " *\n"
261 : << dx << " * Parameters are:\n"
262 : << dx << " * \\param offset number of spaces to shift object right (useful to print nested objects)\n"
263 : << dx << " * \\param print_header if false, do not print object header (to print attributes of base classes)\n"
264 : << dx << " * \\param s output stream\n"
265 : << dx << " */\n\n"
266 : << dx << " virtual void print(unsigned int offset, bool print_header, std::ostream& s) const;\n\n\n"
267 : << dx << " /**\n"
268 : << dx << " * \\brief Get values of relationships and results of some algorithms as a vector of dunedaq::conffwk::DalObject pointers.\n"
269 : << dx << " *\n"
270 : << dx << " * Parameters are:\n"
271 : << dx << " * \\param name name of the relationship or algorithm\n"
272 : << dx << " * \\return value of relationship or result of algorithm\n"
273 : << dx << " * \\throw std::exception if there is no relationship or algorithm with such name in this and base classes\n"
274 : << dx << " */\n\n"
275 : << dx << " virtual std::vector<const dunedaq::conffwk::DalObject *> get(const std::string& name, bool upcast_unregistered = true) const;\n\n\n"
276 : << dx << " protected:\n\n"
277 0 : << dx << " bool get(const std::string& name, std::vector<const dunedaq::conffwk::DalObject *>& vec, bool upcast_unregistered, bool first_call) const;\n\n\n";
278 :
279 :
280 : // generate class attributes and relationships in accordance with
281 : // database schema
282 :
283 0 : if (cl->direct_attributes() || cl->direct_relationships() || cl->direct_methods())
284 : {
285 0 : cpp_file << dx << " private:\n\n";
286 :
287 : // generate attributes:
288 : // - for single attributes this is a normal member variable.
289 : // - for multiple values this is a std::vector<T>.
290 :
291 0 : if (const std::list<oks::OksAttribute*> * alist = cl->direct_attributes())
292 : {
293 0 : for (const auto& i : *alist)
294 : {
295 0 : const std::string aname(alnum_name(i->get_name()));
296 0 : std::string cpp_type = get_type(i->get_data_type(), true);
297 :
298 0 : if (i->get_is_multi_values())
299 0 : cpp_file << dx << " std::vector<" << cpp_type << "> m_" << aname << ";\n";
300 : else
301 0 : cpp_file << dx << " " << cpp_type << " m_" << aname << ";\n";
302 0 : }
303 : }
304 :
305 :
306 : // generate relationships:
307 : // - for single values this is just a pointer.
308 : // - for multiple values this is a vector of pointers.
309 :
310 0 : if (const std::list<oks::OksRelationship*> *rlist = cl->direct_relationships())
311 : {
312 0 : for (const auto& i : *rlist)
313 : {
314 0 : const std::string rname(alnum_name(i->get_name()));
315 0 : const std::string full_class_name(get_full_cpp_class_name(i->get_class_type(), cl_info, cpp_ns_name));
316 0 : if (i->get_high_cardinality_constraint() == oks::OksRelationship::Many)
317 0 : cpp_file << dx << " std::vector<const " << full_class_name << "*> m_" << rname << ";\n";
318 : else
319 0 : cpp_file << dx << " const " << full_class_name << "* m_" << rname << ";\n";
320 0 : }
321 : }
322 :
323 :
324 : // generate methods extension if any
325 :
326 0 : if (const std::list<oks::OksMethod*> * mlist = cl->direct_methods())
327 : {
328 0 : for (const auto& i : *mlist)
329 : {
330 0 : if (oks::OksMethodImplementation * mi = find_cpp_method_implementation(i))
331 : {
332 0 : std::string method_extension = get_private_section(mi);
333 0 : if (!method_extension.empty())
334 : {
335 0 : cpp_file << "\n" << dx << " // extension of method " << cl->get_name() << "::" << i->get_name() << "()\n";
336 0 : print_indented(cpp_file, method_extension, dx2);
337 : }
338 0 : }
339 : }
340 : }
341 :
342 :
343 0 : cpp_file << std::endl << std::endl << dx << " public:\n\n";
344 :
345 :
346 : // generate attribute accessors:
347 : // 1. for each attribute generate static std::string with it's name
348 : // 2a. for single values this is just:
349 : // - attribute_type attribute_name() const { return m_attribute; }
350 : // 2b. for multiple values this is:
351 : // - const std::vector<attribute_type>& attribute_name() const { return m_attribute; }
352 :
353 0 : if (const std::list<oks::OksAttribute*> *alist = cl->direct_attributes())
354 : {
355 :
356 0 : cpp_file << dx << " // attribute names\n\n";
357 :
358 0 : for (const auto& i : *alist)
359 : {
360 0 : const std::string& aname(i->get_name());
361 0 : cpp_file << dx << " inline static const std::string s_" << alnum_name(aname) << " = \"" << aname << "\";\n";
362 : }
363 :
364 0 : cpp_file << "\n";
365 :
366 0 : for (const auto& i : *alist)
367 : {
368 0 : const std::string& cpp_aname(alnum_name(i->get_name()));
369 0 : cpp_file << dx << " static const std::string& __get_" << cpp_aname << "_str() noexcept { return s_" << cpp_aname << "; }\n";
370 0 : }
371 :
372 0 : cpp_file << std::endl << std::endl;
373 :
374 0 : for (const auto& i : *alist)
375 : {
376 0 : const std::string aname(alnum_name(i->get_name()));
377 :
378 : // generate enum values
379 :
380 0 : if (i->get_data_type() == oks::OksData::enum_type && !i->get_range().empty())
381 : {
382 0 : std::string description("Valid enumeration values to compare with value returned by get_");
383 0 : description += aname;
384 0 : description += "() and to pass value to set_";
385 0 : description += aname;
386 0 : description += "() methods.";
387 :
388 0 : print_description(cpp_file, description, dx2);
389 :
390 0 : description += "\nUse toString() method to compare and to pass the values. Do not use name() method.";
391 :
392 0 : cpp_file << dx << " struct " << capitalize_name(aname) << " {\n";
393 :
394 0 : oks::Oks::Tokenizer t(i->get_range(), ",");
395 0 : std::string token;
396 0 : while (!(token = t.next()).empty())
397 : {
398 0 : cpp_file << dx << " inline static const std::string " << capitalize_name(alnum_name(token)) << " = \"" << token << "\";\n";
399 : }
400 :
401 0 : cpp_file << dx << " };\n\n";
402 0 : }
403 :
404 : // generate get method description
405 :
406 0 : {
407 :
408 0 : std::string description("Get \"");
409 0 : description += i->get_name();
410 0 : description += "\" attribute value.\n\n";
411 0 : description += i->get_description();
412 :
413 0 : std::string description2("\\brief ");
414 0 : description2 += description;
415 0 : description2 += "\n\\return the attribute value\n";
416 0 : description2 += "\\throw dunedaq::conffwk::Generic, dunedaq::conffwk::DeletedObject\n";
417 :
418 0 : print_description(cpp_file, description2, dx2);
419 0 : }
420 :
421 : // generate method body
422 :
423 0 : cpp_file << dx << " ";
424 :
425 0 : std::string cpp_type = get_type(i->get_data_type(), true);
426 :
427 0 : if (i->get_is_multi_values())
428 : {
429 0 : cpp_file << "const std::vector<" << cpp_type << ">&";
430 : }
431 : else
432 : {
433 0 : if (cpp_type == "std::string")
434 0 : cpp_file << "const std::string&";
435 : else
436 0 : cpp_file << cpp_type;
437 : }
438 :
439 0 : cpp_file << '\n'
440 : << dx << " get_" << aname << "() const\n"
441 : << dx << " {\n"
442 : << dx << " std::lock_guard scoped_lock(m_mutex);\n"
443 : << dx << " check();\n"
444 : << dx << " check_init();\n"
445 : << dx << " return m_" << aname << ";\n"
446 0 : << dx << " }\n\n";
447 :
448 : // generate set method description
449 :
450 0 : {
451 0 : std::string description("Set \"");
452 0 : description += i->get_name();
453 0 : description += "\" attribute value.\n\n";
454 0 : description += i->get_description();
455 :
456 0 : std::string description2("\\brief ");
457 0 : description2 += description;
458 0 : description2 += "\n\\param value new attribute value\n";
459 0 : description2 += "\\throw dunedaq::conffwk::Generic, dunedaq::conffwk::DeletedObject\n";
460 :
461 0 : print_description(cpp_file, description2, dx2);
462 0 : }
463 :
464 : // generate set method
465 :
466 0 : cpp_file << dx << " void\n" << dx << " set_" << aname << '(';
467 :
468 0 : if (i->get_is_multi_values())
469 : {
470 0 : cpp_file << "const std::vector<" << cpp_type << ">&";
471 : }
472 : else
473 : {
474 0 : if (cpp_type == "std::string")
475 : {
476 0 : cpp_file << "const std::string&";
477 : }
478 : else
479 : {
480 0 : cpp_file << cpp_type;
481 : }
482 : }
483 :
484 0 : cpp_file << " value)\n"
485 : << dx << " {\n"
486 : << dx << " std::lock_guard scoped_lock(m_mutex);\n"
487 : << dx << " check();\n"
488 : << dx << " clear();\n"
489 0 : << dx << " p_obj.";
490 :
491 0 : if (i->get_data_type() == oks::OksData::string_type && i->get_is_multi_values() == false)
492 : {
493 0 : cpp_file << "set_by_ref";
494 : }
495 0 : else if (i->get_data_type() == oks::OksData::enum_type)
496 : {
497 0 : cpp_file << "set_enum";
498 : }
499 0 : else if (i->get_data_type() == oks::OksData::class_type)
500 : {
501 0 : cpp_file << "set_class";
502 : }
503 0 : else if (i->get_data_type() == oks::OksData::date_type)
504 : {
505 0 : cpp_file << "set_date";
506 : }
507 0 : else if (i->get_data_type() == oks::OksData::time_type)
508 : {
509 0 : cpp_file << "set_time";
510 : }
511 : else
512 : {
513 0 : cpp_file << "set_by_val";
514 : }
515 :
516 0 : cpp_file << "(s_" << aname << ", value);\n"
517 0 : << dx << " }\n\n\n";
518 0 : }
519 : }
520 :
521 :
522 : // generate relationship accessors.
523 : // 1. for each relationship generate static std::string with it's name
524 : // 2a. for single values this is just:
525 : // - const relation_type * relation() const { return m_relation; }
526 : // 2b. for multiple values this is:
527 : // - const std::vector<const relation_type*>& relation() const { return m_relation; }
528 :
529 0 : if (const std::list<oks::OksRelationship*> *rlist = cl->direct_relationships())
530 : {
531 :
532 0 : cpp_file << dx << " // relationship names\n\n";
533 :
534 0 : for (const auto& i : *rlist)
535 : {
536 0 : const std::string& rname(i->get_name());
537 0 : cpp_file << dx << " inline static const std::string s_" << alnum_name(rname) << " = \"" << rname << "\";\n";
538 : }
539 :
540 0 : cpp_file << "\n";
541 :
542 0 : for (const auto& i : *rlist)
543 : {
544 0 : const std::string& cpp_rname(alnum_name(i->get_name()));
545 0 : cpp_file << dx << " static const std::string& __get_" << cpp_rname << "_str() noexcept { return s_" << cpp_rname << "; }\n";
546 0 : }
547 :
548 0 : cpp_file << std::endl << std::endl;
549 :
550 0 : for (const auto& i : *rlist)
551 : {
552 :
553 : // generate description
554 :
555 0 : {
556 0 : std::string description("Get \"");
557 0 : description += i->get_name();
558 0 : description += "\" relationship value.\n\n";
559 0 : description += i->get_description();
560 :
561 0 : std::string description2("\\brief ");
562 0 : description2 += description;
563 0 : description2 += "\n\\return the relationship value\n";
564 0 : description2 += "\\throw dunedaq::conffwk::Generic, dunedaq::conffwk::DeletedObject\n";
565 :
566 0 : print_description(cpp_file, description2, dx2);
567 0 : }
568 :
569 : // generate method body
570 :
571 0 : cpp_file << dx << " const ";
572 :
573 0 : const std::string rname(alnum_name(i->get_name()));
574 0 : std::string full_cpp_class_name = get_full_cpp_class_name(i->get_class_type(), cl_info, cpp_ns_name);
575 :
576 0 : if (i->get_high_cardinality_constraint() == oks::OksRelationship::Many)
577 : {
578 0 : cpp_file << "std::vector<const " << full_cpp_class_name << "*>&";
579 : }
580 : else
581 : {
582 0 : cpp_file << full_cpp_class_name << " *";
583 : }
584 :
585 0 : cpp_file << "\n"
586 : << dx << " get_" << rname << "() const\n"
587 : << dx << " {\n"
588 : << dx << " std::lock_guard scoped_lock(m_mutex);\n"
589 : << dx << " check();\n"
590 0 : << dx << " check_init();\n";
591 :
592 0 : if (i->get_low_cardinality_constraint() == oks::OksRelationship::One)
593 : {
594 0 : if (i->get_high_cardinality_constraint() == oks::OksRelationship::One)
595 : {
596 0 : cpp_file
597 : << dx << " if (!m_" << rname << ")\n"
598 : << dx << " {\n"
599 : << dx << " std::ostringstream text;\n"
600 : << dx << " text << \"relationship \\\"\" << s_" << rname << " << \"\\\" of object \" << this << \" is not set\";\n"
601 : << dx << " throw dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str());\n"
602 0 : << dx << " }\n";
603 : }
604 : else
605 : {
606 0 : cpp_file
607 : << dx << " if (m_" << rname << ".empty())\n"
608 : << dx << " {\n"
609 : << dx << " std::ostringstream text;\n"
610 : << dx << " text << \"relationship \\\"\" << s_" << rname << " << \"\\\" of object \" << this << \" is empty\";\n"
611 : << dx << " throw dunedaq::conffwk::Generic(ERS_HERE, text.str().c_str());\n"
612 0 : << dx << " }\n";
613 : }
614 : }
615 :
616 0 : cpp_file
617 : << dx << " return m_" << rname << ";\n"
618 0 : << dx << " }\n\n\n";
619 :
620 : // generate set method
621 :
622 0 : {
623 0 : std::string description("Set \"");
624 0 : description += i->get_name();
625 0 : description += "\" relationship value.\n\n";
626 0 : description += i->get_description();
627 :
628 0 : std::string description2("\\brief ");
629 0 : description2 += description;
630 0 : description2 += "\n\\param value new relationship value\n";
631 0 : description2 += "\\throw dunedaq::conffwk::Generic, dunedaq::conffwk::DeletedObject\n";
632 :
633 0 : print_description(cpp_file, description2, dx2);
634 0 : }
635 :
636 0 : cpp_file << dx << " void\n" << dx << " set_" << rname << "(const ";
637 :
638 0 : if (i->get_high_cardinality_constraint() == oks::OksRelationship::Many)
639 : {
640 0 : cpp_file << "std::vector<const " << full_cpp_class_name << "*>&";
641 : }
642 : else
643 : {
644 0 : cpp_file << full_cpp_class_name << " *";
645 : }
646 :
647 0 : cpp_file << " value);\n\n";
648 0 : }
649 : }
650 : }
651 :
652 :
653 : // generate methods
654 :
655 0 : if (const std::list<oks::OksMethod*> *mlist = cl->direct_methods())
656 : {
657 0 : bool cpp_comment_is_printed = false;
658 :
659 0 : for (const auto& i : *mlist)
660 : {
661 :
662 : // C++ algorithms
663 :
664 0 : if (oks::OksMethodImplementation * mi = find_cpp_method_implementation(i))
665 : {
666 0 : if (cpp_comment_is_printed == false)
667 : {
668 0 : cpp_file << std::endl << dx << " public:\n\n" << dx << " // user-defined algorithms\n\n";
669 : cpp_comment_is_printed = true;
670 : }
671 : else
672 : {
673 0 : cpp_file << "\n\n";
674 : }
675 :
676 : // generate description
677 :
678 0 : print_description(cpp_file, i->get_description(), dx2);
679 :
680 : // generate prototype
681 :
682 0 : cpp_file << dx << " " << mi->get_prototype() << ";\n";
683 :
684 :
685 : // generate public section extension
686 :
687 0 : std::string public_method_extension = get_public_section(mi);
688 0 : if (!public_method_extension.empty())
689 : {
690 0 : cpp_file << "\n" << " // extension of method " << cl->get_name() << "::" << i->get_name() << "()\n";
691 0 : print_indented(cpp_file, public_method_extension, " ");
692 : }
693 0 : }
694 :
695 : }
696 : }
697 :
698 :
699 : // class finished
700 :
701 0 : cpp_file << dx << "};\n\n";
702 :
703 :
704 : // generate ostream operators and typedef for iterator
705 :
706 0 : cpp_file
707 : << dx << " // out stream operator\n\n"
708 : << dx << "inline std::ostream& operator<<(std::ostream& s, const " << name << "& obj)\n"
709 : << dx << " {\n"
710 : << dx << " return obj.print_object(s);\n"
711 : << dx << " }\n\n"
712 0 : << dx << "typedef std::vector<const " << name << "*>::const_iterator " << name << "Iterator;\n\n";
713 :
714 :
715 : // close namespace
716 :
717 0 : close_cpp_namespace(cpp_file, ns_level);
718 :
719 :
720 : // generate methods epilogues if necessary
721 :
722 0 : if (const std::list<oks::OksMethod*> * mlist = cl->direct_methods())
723 : {
724 0 : for (const auto & i : *mlist)
725 : {
726 0 : oks::OksMethodImplementation * mi = find_cpp_method_implementation(i);
727 0 : if (mi && !get_method_header_epilogue(mi).empty())
728 : {
729 0 : cpp_file << " // epilogue of method " << cl->get_name() << "::" << i->get_name() << "()\n";
730 0 : cpp_file << get_method_header_epilogue(mi) << std::endl;
731 : }
732 : }
733 : }
734 :
735 0 : }
736 :
737 :
738 : static void
739 : set2out(std::ostream& out, const std::set<std::string>& data, bool& is_first)
740 : {
741 : for (const auto& x : data)
742 : {
743 : if (is_first)
744 : is_first = false;
745 : else
746 : out << ',';
747 : out << '\"' << x << "()\"";
748 : }
749 : }
750 :
751 :
752 : static void
753 0 : gen_cpp_body(const oks::OksClass *cl, std::ostream& cpp_s, const std::string& cpp_ns_name, const std::string& cpp_hdr_dir, const ClassInfo::Map& cl_info)
754 : {
755 0 : cpp_s << "#include \"logging/Logging.hpp\"\n\n";
756 :
757 0 : const std::string name(alnum_name(cl->get_name()));
758 :
759 0 : std::set<oks::OksClass *> rclasses;
760 :
761 : // for each relationship, include the header file
762 :
763 0 : if (const std::list<oks::OksRelationship*> * rlist = cl->direct_relationships())
764 : {
765 0 : for (const auto& i : *rlist)
766 : {
767 0 : oks::OksClass * c = i->get_class_type();
768 0 : if (has_superclass(cl, c) == false && cl != c)
769 : {
770 0 : rclasses.insert(c);
771 : }
772 : }
773 : }
774 :
775 0 : if (const std::list<oks::OksMethod*> * mlist = cl->direct_methods())
776 : {
777 0 : for (const auto& i : *mlist)
778 : {
779 0 : if (oks::OksMethodImplementation * mi = find_cpp_method_implementation(i))
780 : {
781 0 : std::string prototype(mi->get_prototype());
782 0 : std::string::size_type idx = prototype.find('(');
783 :
784 0 : if (get_add_algo_n(mi) || get_add_algo_1(mi))
785 : {
786 :
787 0 : if (idx != std::string::npos)
788 : {
789 0 : idx--;
790 :
791 : // skip spaces between method name and ()
792 0 : while (isspace(prototype[idx]) && idx > 0)
793 0 : idx--;
794 :
795 : // find beginning of the method name
796 0 : while (!isspace(prototype[idx]) && idx > 0)
797 0 : idx--;
798 :
799 : // remove method name and arguments
800 0 : prototype.erase(idx + 1);
801 :
802 : // remove spaces
803 0 : prototype.erase(std::remove_if(prototype.begin(), prototype.end(), [](unsigned char x)
804 0 : { return std::isspace(x);}), prototype.end());
805 :
806 0 : if (prototype.empty() == false)
807 : {
808 0 : idx = prototype.find('*');
809 0 : prototype.erase(idx--);
810 :
811 0 : if (idx != std::string::npos)
812 : {
813 0 : while (isalnum(prototype[idx]) && idx > 0)
814 0 : idx--;
815 :
816 0 : if(idx == 0 && get_add_algo_1(mi) && prototype.find("const") == 0)
817 0 : prototype.erase(0, 5);
818 : else
819 0 : prototype.erase(0, idx+1);
820 :
821 0 : if (oks::OksClass * c = cl->get_kernel()->find_class(prototype))
822 0 : rclasses.insert(c);
823 : }
824 : }
825 : }
826 : }
827 0 : }
828 : }
829 : }
830 :
831 0 : if (!rclasses.empty())
832 : {
833 0 : cpp_s << " // include files for classes used in relationships and algorithms\n\n";
834 :
835 0 : for (const auto& j : rclasses)
836 : {
837 0 : cpp_s << "#include \"" << get_include_dir(j, cl_info, cpp_hdr_dir) << ".hpp\"\n";
838 : }
839 :
840 0 : cpp_s << std::endl << std::endl;
841 : }
842 :
843 :
844 : // open namespace
845 :
846 0 : int ns_level = open_cpp_namespace(cpp_s, cpp_ns_name);
847 0 : std::string ns_dx = int2dx(ns_level);
848 0 : std::string ns_dx2 = ns_dx + " ";
849 :
850 0 : const char * dx = ns_dx.c_str(); // are used for alignment
851 0 : const char * dx2 = ns_dx2.c_str();
852 :
853 :
854 : // static objects
855 :
856 0 : cpp_s << dx << "const std::string& " << name << "::s_class_name(dunedaq::conffwk::DalFactory::instance().get_known_class_name_ref(\"" << name << "\"));\n\n";
857 :
858 0 : std::set<std::string> algo_n_set, algo_1_set;
859 :
860 0 : if (const std::list<oks::OksMethod*> * mlist = cl->direct_methods())
861 : {
862 0 : for (const auto& i : *mlist)
863 : {
864 0 : if(oks::OksMethodImplementation * mi = find_cpp_method_implementation(i))
865 : {
866 0 : std::string prototype(mi->get_prototype());
867 0 : std::string::size_type idx = prototype.find('(');
868 :
869 0 : if (idx != std::string::npos)
870 : {
871 0 : idx--;
872 :
873 : // skip spaces between method name and ()
874 0 : while (isspace(prototype[idx]) && idx > 0)
875 0 : idx--;
876 :
877 : // remove method arguments
878 0 : prototype.erase(idx+1);
879 :
880 : // find beginning of the method name
881 0 : while (!isspace(prototype[idx]) && idx > 0)
882 0 : idx--;
883 :
884 0 : if (idx > 0)
885 : {
886 0 : prototype.erase(0, idx+1);
887 :
888 0 : if (get_add_algo_n(mi))
889 : {
890 0 : algo_n_set.insert(prototype);
891 : }
892 0 : else if (get_add_algo_1(mi))
893 : {
894 0 : algo_1_set.insert(prototype);
895 : }
896 : }
897 : }
898 0 : }
899 : }
900 : }
901 :
902 :
903 0 : if ( !cl->get_is_abstract() ) {
904 0 : cpp_s
905 : << dx << " // the factory initializer\n\n"
906 : << dx << "static struct __" << name << "_Registrator\n"
907 : << dx << " {\n"
908 : << dx << " __" << name << "_Registrator()\n"
909 : << dx << " {\n"
910 0 : << dx << " dunedaq::conffwk::DalFactory::instance().register_dal_class<" << name << ">(\"" << cl->get_name() << "\");\n"
911 : << dx << " }\n"
912 0 : << dx << " } registrator;\n\n\n";
913 : }
914 :
915 : // the constructor
916 :
917 0 : cpp_s
918 : << dx << " // the constructor\n\n"
919 : << dx << name << "::" << name << "(conffwk::DalRegistry& db, const conffwk::ConfigObject& o) noexcept :\n"
920 0 : << dx << " " << "dunedaq::conffwk::DalObject(db, o)";
921 :
922 :
923 : // fill member initializer list, if any
924 :
925 0 : std::list<std::string> initializer_list;
926 :
927 0 : if(const std::list<std::string*> * slist = cl->direct_super_classes())
928 : {
929 0 : for(auto & i : *slist)
930 : {
931 0 : initializer_list.push_back(get_full_cpp_class_name(cl->get_kernel()->find_class(*i), cl_info, "") + "(db, o)");
932 : }
933 : }
934 :
935 0 : if (const std::list<oks::OksRelationship *> *rlist = cl->direct_relationships())
936 : {
937 0 : for (std::list<oks::OksRelationship*>::const_iterator i = rlist->begin(); i != rlist->end(); ++i)
938 : {
939 0 : if ((*i)->get_high_cardinality_constraint() != oks::OksRelationship::Many)
940 : {
941 0 : initializer_list.push_back(std::string("m_") + alnum_name((*i)->get_name()) + " (nullptr)");
942 : }
943 : }
944 : }
945 :
946 :
947 0 : if(const std::list<oks::OksMethod*> * mlist = cl->direct_methods())
948 : {
949 0 : for (std::list<oks::OksMethod*>::const_iterator i = mlist->begin(); i != mlist->end(); ++i)
950 : {
951 0 : if (oks::OksMethodImplementation * mi = find_cpp_method_implementation(*i))
952 : {
953 0 : std::string member_initializer = get_member_initializer_list(mi);
954 0 : member_initializer.erase(remove(member_initializer.begin(), member_initializer.end(), '\n'), member_initializer.end());
955 :
956 0 : if (!member_initializer.empty())
957 : {
958 0 : initializer_list.push_back(member_initializer);
959 : }
960 0 : }
961 : }
962 : }
963 :
964 0 : if (initializer_list.empty() == false)
965 : {
966 0 : for (auto & i : initializer_list)
967 : {
968 0 : cpp_s << ",\n" << dx << " " << i;
969 : }
970 :
971 0 : cpp_s << std::endl;
972 : }
973 :
974 0 : cpp_s << "\n"
975 : << dx << "{\n"
976 : << dx << " ;\n"
977 0 : << dx << "}\n\n\n";
978 :
979 :
980 : // print method
981 :
982 0 : cpp_s
983 : << dx << "void " << name << "::print(unsigned int indent, bool print_header, std::ostream& s) const\n"
984 : << dx << "{\n"
985 : << dx << " check_init();\n\n"
986 0 : << dx << " try {\n";
987 :
988 0 : if (cl->direct_attributes() || cl->direct_relationships())
989 0 : cpp_s << dx << " const std::string str(indent+2, ' ');\n";
990 :
991 0 : cpp_s
992 : << '\n'
993 : << dx << " if (print_header)\n"
994 0 : << dx << " p_hdr(s, indent, s_class_name";
995 :
996 0 : if(!cpp_ns_name.empty()) {
997 0 : cpp_s << ", \"" << cpp_ns_name << '\"';
998 : }
999 :
1000 0 : cpp_s << ");\n";
1001 :
1002 :
1003 0 : if (const std::list<std::string*> * slist = cl->direct_super_classes())
1004 : {
1005 0 : cpp_s << "\n\n" << dx << " // print direct super-classes\n\n";
1006 :
1007 0 : for (const auto& i : *slist)
1008 0 : cpp_s << dx << " " << get_full_cpp_class_name(cl->get_kernel()->find_class(*i), cl_info, cpp_ns_name) << "::print(indent, false, s);\n";
1009 : }
1010 :
1011 0 : if(const std::list<oks::OksAttribute*> * alist = cl->direct_attributes()) {
1012 0 : cpp_s << "\n\n" << dx << " // print direct attributes\n\n";
1013 :
1014 0 : for(const auto& i : *alist) {
1015 0 : const std::string aname(alnum_name(i->get_name()));
1016 0 : std::string abase = (i->get_format() == oks::OksAttribute::Hex) ? "<dunedaq::conffwk::hex>" : (i->get_format() == oks::OksAttribute::Oct) ? "<dunedaq::conffwk::oct>" : "";
1017 :
1018 0 : if (i->get_is_multi_values())
1019 0 : cpp_s << dx << " dunedaq::conffwk::p_mv_attr" << abase << "(s, str, s_" << aname << ", m_" << aname << ");\n";
1020 : else
1021 0 : cpp_s << dx << " dunedaq::conffwk::p_sv_attr" << abase << "(s, str, s_" << aname << ", m_" << aname << ");\n";
1022 0 : }
1023 : }
1024 :
1025 0 : if (const std::list<oks::OksRelationship*> * rlist = cl->direct_relationships())
1026 : {
1027 0 : cpp_s << "\n\n" << dx << " // print direct relationships\n\n";
1028 :
1029 0 : for (const auto& i : *rlist)
1030 : {
1031 0 : const std::string rname(alnum_name(i->get_name()));
1032 :
1033 0 : if (i->get_high_cardinality_constraint() == oks::OksRelationship::Many)
1034 : {
1035 0 : if (i->get_is_composite())
1036 0 : cpp_s << dx << " dunedaq::conffwk::p_mv_rel(s, str, indent, s_" << rname << ", m_" << rname << ");\n";
1037 : else
1038 0 : cpp_s << dx << " dunedaq::conffwk::p_mv_rel(s, str, s_" << rname << ", m_" << rname << ");\n";
1039 : }
1040 : else
1041 : {
1042 0 : if (i->get_is_composite())
1043 0 : cpp_s << dx <<" dunedaq::conffwk::p_sv_rel(s, str, indent, s_" << rname << ", m_" << rname << ");\n";
1044 : else
1045 0 : cpp_s << dx <<" dunedaq::conffwk::p_sv_rel(s, str, s_" << rname << ", m_" << rname << ");\n";
1046 : }
1047 0 : }
1048 : }
1049 :
1050 0 : cpp_s << dx << " }\n"
1051 : << dx << " catch (dunedaq::conffwk::Exception & ex) {\n"
1052 : << dx << " dunedaq::conffwk::DalObject::p_error(s, ex);\n"
1053 : << dx << " }\n"
1054 0 : << dx << "}\n\n\n";
1055 :
1056 :
1057 : // init method
1058 :
1059 0 : {
1060 0 : const char * ic_value = (
1061 0 : ( cl->direct_relationships() && cl->direct_relationships()->size() ) ||
1062 0 : ( cl->direct_super_classes() && cl->direct_super_classes()->size() )
1063 0 : ? "init_children"
1064 : : "/* init_children */"
1065 0 : );
1066 :
1067 0 : cpp_s
1068 : << dx << "void " << name << "::init(bool " << ic_value << ")\n"
1069 0 : << dx << "{\n";
1070 : }
1071 :
1072 0 : if (cl->direct_super_classes() == nullptr)
1073 : {
1074 0 : cpp_s
1075 : << dx << " p_was_read = true;\n"
1076 0 : << dx << " increment_read();\n";
1077 : }
1078 :
1079 : // generate initialization for super classes
1080 :
1081 0 : if (const std::list<std::string*> * slist = cl->direct_super_classes())
1082 : {
1083 0 : for (const auto& i : *slist)
1084 : {
1085 0 : cpp_s << dx << " " << alnum_name(*i) << "::init(init_children);\n";
1086 : }
1087 0 : if (!slist->empty())
1088 0 : cpp_s << std::endl;
1089 : }
1090 :
1091 0 : cpp_s << dx << " TLOG_DEBUG(5) << \"read object \" << this << \" (class \" << s_class_name << \')\';\n";
1092 :
1093 : // put try / catch only if there are attributes or relationships to be initialized
1094 0 : const std::list<oks::OksAttribute*> *alist = cl->direct_attributes();
1095 0 : const std::list<oks::OksRelationship*> *rlist = cl->direct_relationships();
1096 :
1097 0 : if ((alist && !alist->empty()) || (rlist && !rlist->empty()))
1098 : {
1099 0 : cpp_s << std::endl << dx << " try {\n";
1100 :
1101 :
1102 : // generate initialization for attributes
1103 0 : if (alist)
1104 : {
1105 0 : for (const auto& i : *alist)
1106 : {
1107 0 : const std::string cpp_name = alnum_name(i->get_name());
1108 0 : cpp_s << dx << " p_obj.get(s_" << cpp_name << ", m_" << cpp_name << ");\n";
1109 0 : }
1110 : }
1111 :
1112 :
1113 : // generate initialization for relationships
1114 0 : if (rlist)
1115 : {
1116 0 : for (const auto& i : *rlist)
1117 : {
1118 0 : const std::string& rname = i->get_name();
1119 0 : std::string cpp_name = alnum_name(rname);
1120 0 : std::string rcname = get_full_cpp_class_name(i->get_class_type(), cl_info, cpp_ns_name);
1121 0 : if (i->get_high_cardinality_constraint() == oks::OksRelationship::Many)
1122 : {
1123 0 : cpp_s << dx << " p_registry._ref<" << rcname << ">(p_obj, s_" << cpp_name << ", " << "m_" << cpp_name << ", init_children);\n";
1124 : }
1125 : else
1126 : {
1127 0 : cpp_s << dx << " m_" << cpp_name << " = p_registry._ref<" << rcname << ">(p_obj, s_" << cpp_name << ", init_children);\n";
1128 : }
1129 0 : }
1130 : }
1131 :
1132 0 : cpp_s
1133 : << dx << " }\n"
1134 : << dx << " catch (dunedaq::conffwk::Exception & ex) {\n"
1135 : << dx << " throw_init_ex(ex);\n"
1136 0 : << dx << " }\n";
1137 :
1138 : }
1139 :
1140 0 : cpp_s << dx << "}\n\n";
1141 :
1142 :
1143 : // destructor
1144 :
1145 0 : cpp_s
1146 : << dx << name << "::~" << name << "() noexcept\n"
1147 : << dx << "{\n"
1148 0 : << dx << "}\n\n";
1149 :
1150 0 : cpp_s
1151 : << dx << "std::vector<const dunedaq::conffwk::DalObject *> " << name << "::get(const std::string& name, bool upcast_unregistered) const\n"
1152 : << dx << "{\n"
1153 : << dx << " std::vector<const dunedaq::conffwk::DalObject *> vec;\n\n"
1154 : << dx << " if (!get(name, vec, upcast_unregistered, true))\n"
1155 : << dx << " throw_get_ex(name, s_class_name, this);\n\n"
1156 : << dx << " return vec;\n"
1157 0 : << dx << "}\n\n";
1158 :
1159 0 : cpp_s
1160 : << dx << "bool " << name << "::get(const std::string& name, std::vector<const dunedaq::conffwk::DalObject *>& vec, bool upcast_unregistered, bool first_call) const\n"
1161 : << dx << "{\n"
1162 : << dx << " if (first_call)\n"
1163 : << dx << " {\n"
1164 : << dx << " std::lock_guard scoped_lock(m_mutex);\n\n"
1165 : << dx << " check();\n"
1166 : << dx << " check_init();\n\n"
1167 : << dx << " if (get_rel_objects(name, upcast_unregistered, vec))\n"
1168 : << dx << " return true;\n"
1169 0 : << dx << " }\n\n";
1170 :
1171 :
1172 0 : for (const auto &prototype : algo_n_set)
1173 0 : cpp_s
1174 : << dx << " if (name == \"" << prototype << "()\")\n"
1175 : << dx << " {\n"
1176 : << dx << " p_registry.downcast_dal_objects(" << prototype << "(), upcast_unregistered, vec);\n"
1177 : << dx << " return true;\n"
1178 0 : << dx << " }\n\n";
1179 :
1180 0 : for (const auto &prototype : algo_1_set)
1181 0 : cpp_s
1182 : << dx << " if (name == \"" << prototype << "()\")\n"
1183 : << dx << " {\n"
1184 : << dx << " p_registry.downcast_dal_object(" << prototype << "(), upcast_unregistered, vec);\n"
1185 : << dx << " return true;\n"
1186 0 : << dx << " }\n\n";
1187 :
1188 :
1189 0 : if (const std::list<std::string*> * slist = cl->direct_super_classes())
1190 : {
1191 0 : for (const auto& i : *slist)
1192 : {
1193 0 : cpp_s << dx << " if (" << alnum_name(*i) << "::get(name, vec, upcast_unregistered, false)) return true;\n";
1194 : }
1195 :
1196 0 : cpp_s << "\n";
1197 : }
1198 :
1199 0 : cpp_s
1200 : << dx << " if (first_call)\n"
1201 : << dx << " return get_algo_objects(name, vec);\n\n"
1202 : << dx << " return false;\n"
1203 0 : << dx << "}\n\n";
1204 :
1205 :
1206 : // generate relationship set methods
1207 :
1208 0 : if (const std::list<oks::OksRelationship*> *rlist = cl->direct_relationships())
1209 : {
1210 0 : for (const auto& i : *rlist)
1211 : {
1212 0 : const std::string rname(alnum_name(i->get_name()));
1213 0 : std::string full_cpp_class_name = get_full_cpp_class_name(i->get_class_type(), cl_info, cpp_ns_name);
1214 :
1215 0 : cpp_s << dx << "void " << name << "::set_" << rname << "(const ";
1216 :
1217 0 : if (i->get_high_cardinality_constraint() == oks::OksRelationship::Many)
1218 : {
1219 0 : cpp_s
1220 : << "std::vector<const " << full_cpp_class_name << "*>& value)\n"
1221 : << dx << "{\n"
1222 : << dx << " _set_objects(s_" << rname << ", value);\n"
1223 0 : << dx << "}\n\n";
1224 : }
1225 : else
1226 : {
1227 0 : cpp_s
1228 : << full_cpp_class_name << " * value)\n"
1229 : << dx << "{\n"
1230 : << dx << " _set_object(s_" << rname << ", value);\n"
1231 0 : << dx << "}\n\n";
1232 : }
1233 0 : }
1234 : }
1235 :
1236 :
1237 : // generate methods for c++
1238 :
1239 0 : if (const std::list<oks::OksMethod*> * mlist = cl->direct_methods())
1240 : {
1241 0 : bool comment_is_printed = false;
1242 0 : for (const auto& i : *mlist)
1243 : {
1244 0 : oks::OksMethodImplementation * mi = find_cpp_method_implementation(i);
1245 :
1246 0 : if (mi && !get_method_implementation_body(mi).empty())
1247 : {
1248 0 : if (comment_is_printed == false)
1249 : {
1250 0 : cpp_s << dx << " // user-defined algorithms\n\n";
1251 : comment_is_printed = true;
1252 : }
1253 :
1254 : // generate description
1255 :
1256 0 : print_description(cpp_s, i->get_description(), dx2);
1257 :
1258 : // generate prototype
1259 :
1260 0 : std::string prototype(mi->get_prototype());
1261 0 : std::string::size_type idx = prototype.find('(');
1262 :
1263 0 : if (idx != std::string::npos)
1264 : {
1265 0 : idx--;
1266 :
1267 : // skip spaces between method name and ()
1268 :
1269 0 : while (isspace(prototype[idx]) && idx > 0)
1270 0 : idx--;
1271 :
1272 : // find beginning of the method name
1273 :
1274 0 : while ((isalnum(prototype[idx]) || prototype[idx] == '_') && idx > 0)
1275 0 : idx--;
1276 :
1277 0 : prototype[idx] = '\n';
1278 0 : std::string s(dx);
1279 0 : s += alnum_name(name);
1280 0 : s += "::";
1281 0 : prototype.insert(idx + 1, s);
1282 0 : }
1283 :
1284 : // Second pass
1285 0 : std::string::size_type idx_open_bracket = prototype.find('(');
1286 0 : std::string::size_type idx_space = prototype.rfind(' ', idx_open_bracket);
1287 0 : std::string::size_type idx_close_bracket = prototype.rfind(')');
1288 :
1289 0 : auto prototype_attrs = prototype.substr(0,idx_space+1);
1290 0 : auto prototype_head = prototype.substr(idx_space+1,idx_close_bracket-idx_space);
1291 0 : auto prototype_specs = prototype.substr(idx_close_bracket+1);
1292 :
1293 0 : for ( const auto& spec : cpp_method_virtual_specifiers ) {
1294 0 : idx = prototype_attrs.find(spec);
1295 0 : if ( idx != std::string::npos) {
1296 0 : prototype_attrs.erase(idx,spec.size());
1297 : }
1298 0 : prototype_attrs = trim(prototype_attrs);
1299 :
1300 0 : idx = prototype_specs.find(spec);
1301 0 : if ( idx != std::string::npos) {
1302 0 : prototype_specs.erase(idx,spec.size());
1303 : }
1304 0 : prototype_specs = trim(prototype_specs);
1305 : }
1306 :
1307 0 : prototype = prototype_attrs + ' ' + prototype_head + ' ' + prototype_specs;
1308 :
1309 0 : cpp_s
1310 0 : << dx << prototype << std::endl
1311 : << dx << "{\n"
1312 0 : << get_method_implementation_body(mi) << std::endl
1313 0 : << dx << "}\n\n";
1314 0 : }
1315 : }
1316 : }
1317 :
1318 :
1319 : // close namespace
1320 :
1321 0 : close_cpp_namespace(cpp_s, ns_level);
1322 0 : }
1323 :
1324 : static void
1325 0 : load_schemas(oks::OksKernel& kernel, const std::list<std::string>& file_names, std::set<oks::OksFile *, std::less<oks::OksFile *> >& file_hs)
1326 : {
1327 0 : for (const auto& i : file_names)
1328 : {
1329 0 : if (oks::OksFile * fh = kernel.load_schema(i))
1330 : {
1331 0 : file_hs.insert(fh);
1332 : }
1333 : else
1334 : {
1335 0 : std::cerr << "ERROR: can not load schema file \"" << i << "\"\n";
1336 0 : exit(EXIT_FAILURE);
1337 : }
1338 : }
1339 0 : }
1340 :
1341 : static void
1342 0 : gen_cpp_header_prologue(const std::string& file_name,
1343 : std::ostream& s,
1344 : const std::string& cpp_ns_name,
1345 : const std::string& cpp_hdr_dir)
1346 : {
1347 0 : s <<
1348 : "// *** this file is generated by oksdalgen, do not modify it ***\n\n"
1349 :
1350 0 : "#ifndef _" << alnum_name(file_name) << "_0_" << alnum_name(cpp_ns_name) << "_0_" << alnum_name(cpp_hdr_dir) << "_H_\n"
1351 0 : "#define _" << alnum_name(file_name) << "_0_" << alnum_name(cpp_ns_name) << "_0_" << alnum_name(cpp_hdr_dir) << "_H_\n\n"
1352 :
1353 : "#include <stdint.h> // to define 64 bits types\n"
1354 : "#include <iostream>\n"
1355 : "#include <sstream>\n"
1356 : "#include <string>\n"
1357 : "#include <map>\n"
1358 : "#include <vector>\n\n"
1359 :
1360 : "#include \"conffwk/Configuration.hpp\"\n"
1361 0 : "#include \"conffwk/DalObject.hpp\"\n\n";
1362 0 : }
1363 :
1364 :
1365 : static void
1366 0 : gen_cpp_header_epilogue(std::ostream& s)
1367 : {
1368 0 : s << "\n#endif\n";
1369 0 : }
1370 :
1371 :
1372 : static void
1373 0 : gen_cpp_body_prologue(const std::string& file_name,
1374 : std::ostream& src,
1375 : const std::string& cpp_hdr_dir)
1376 : {
1377 0 : src <<
1378 : "#include \"conffwk/ConfigObject.hpp\"\n"
1379 : "#include \"conffwk/DalFactory.hpp\"\n"
1380 : "#include \"conffwk/DalObjectPrint.hpp\"\n"
1381 : "#include \"conffwk/Errors.hpp\"\n"
1382 0 : "#include \"";
1383 0 : if(cpp_hdr_dir != "") {
1384 0 : src << cpp_hdr_dir << "/";
1385 : }
1386 0 : src << file_name << ".hpp\"\n\n";
1387 0 : }
1388 :
1389 :
1390 : int
1391 0 : main(int argc, char *argv[])
1392 : {
1393 0 : std::list<std::string> class_names;
1394 0 : std::list<std::string> file_names;
1395 0 : std::list<std::string> include_dirs;
1396 0 : std::list<std::string> user_classes;
1397 :
1398 0 : std::string cpp_dir_name = "."; // directory for c++ implementation files
1399 0 : std::string cpp_hdr_dir = ""; // directory for c++ header files
1400 0 : std::string cpp_ns_name = ""; // c++ namespace
1401 0 : std::string info_file_name = "oksdalgen.info"; // name of info file
1402 0 : bool verbose = false;
1403 :
1404 0 : parse_arguments(argc, argv, class_names, file_names, include_dirs, user_classes, cpp_dir_name, cpp_ns_name, cpp_hdr_dir, info_file_name, verbose);
1405 :
1406 : // init OKS
1407 :
1408 0 : std::set<oks::OksFile *, std::less<oks::OksFile *> > file_hs;
1409 :
1410 0 : oks::OksKernel kernel(false, false, false, false);
1411 :
1412 0 : try
1413 : {
1414 0 : load_schemas(kernel, file_names, file_hs);
1415 :
1416 : // if no user defined classes, generate all
1417 :
1418 0 : if (class_names.size() == 0)
1419 : {
1420 0 : if (verbose)
1421 : {
1422 0 : std::cout << "No explicit classes were provided,\n"
1423 0 : "search for classes which belong to the given schema files:\n";
1424 : }
1425 :
1426 0 : const oks::OksClass::Map& class_list = kernel.classes();
1427 :
1428 0 : if (!class_list.empty())
1429 : {
1430 0 : for (const auto& i : class_list)
1431 : {
1432 0 : if (verbose)
1433 : {
1434 0 : std::cout << " * check for class \"" << i.first << "\" ";
1435 : }
1436 :
1437 0 : if (file_hs.find(i.second->get_file()) != file_hs.end())
1438 : {
1439 0 : class_names.push_back(i.second->get_name());
1440 0 : if (verbose)
1441 : {
1442 0 : std::cout << "OK\n";
1443 : }
1444 : }
1445 : else
1446 : {
1447 0 : if (verbose)
1448 : {
1449 0 : std::cout << "skip\n";
1450 : }
1451 : }
1452 : }
1453 : }
1454 : else
1455 : {
1456 0 : std::cerr << "No classes in schema file and no user classes specified\n";
1457 0 : exit(EXIT_FAILURE);
1458 : }
1459 : }
1460 :
1461 : // calculate set of classes which should be mentioned by the generator;
1462 : // note, some of classes can come from other DALs
1463 :
1464 0 : typedef std::set<const oks::OksClass *, std::less<const oks::OksClass *> > Set;
1465 0 : Set generated_classes;
1466 0 : ClassInfo::Map cl_info;
1467 :
1468 0 : unsigned int error_num = 0;
1469 :
1470 : // build set of classes which are generated
1471 :
1472 0 : for (const auto& i : class_names)
1473 : {
1474 0 : if (oks::OksClass *cl = kernel.find_class(i))
1475 : {
1476 0 : generated_classes.insert(cl);
1477 : }
1478 : else
1479 : {
1480 0 : std::cerr << "ERROR: can not find class " << i << std::endl;
1481 0 : error_num++;
1482 : }
1483 : }
1484 :
1485 : // build set of classes which are external to generated
1486 :
1487 0 : for (const auto& i : generated_classes)
1488 : {
1489 0 : if (const std::list<oks::OksRelationship *> * rels = i->direct_relationships())
1490 : {
1491 0 : for (const auto& j : *rels)
1492 : {
1493 0 : const oks::OksClass * rc = j->get_class_type();
1494 :
1495 0 : if (rc == 0)
1496 : {
1497 0 : std::cerr << "\nERROR: the class \"" << j->get_type() << "\" (it is used by the relationship \"" << j->get_name() << "\" of class \"" << i->get_name() << "\") is not defined by the schema.\n";
1498 0 : error_num++;
1499 : }
1500 0 : else if (generated_classes.find(rc) == generated_classes.end())
1501 : {
1502 0 : if (process_external_class(cl_info, rc, include_dirs, user_classes, verbose) == false)
1503 : {
1504 0 : std::cerr << "\nERROR: the class \"" << j->get_type() << "\" is used by the relationship \"" << j->get_name() << "\" of class \"" << i->get_name() << "\".\n"
1505 : " The class is not in the list of generated classes, "
1506 : "it was not found among already generated headers "
1507 : "(search list is defined by the -I | --include-dirs parameter) and "
1508 0 : "it is not defined by user via -D | --user-defined-classes.\n";
1509 0 : error_num++;
1510 : }
1511 : }
1512 : }
1513 : }
1514 :
1515 0 : if (const std::list<std::string *> * sclasses = i->direct_super_classes())
1516 : {
1517 0 : for (const auto& j : *sclasses)
1518 : {
1519 0 : const oks::OksClass * rc = kernel.find_class(*j);
1520 :
1521 0 : if (rc == 0)
1522 : {
1523 0 : std::cerr << "\nERROR: the class \"" << *j << "\" (it is direct superclass of class \"" << i->get_name() << "\") is not defined by the schema.\n";
1524 0 : error_num++;
1525 : }
1526 0 : else if (generated_classes.find(rc) == generated_classes.end())
1527 : {
1528 0 : if (process_external_class(cl_info, rc, include_dirs, user_classes, verbose) == false)
1529 : {
1530 0 : std::cerr << "\nERROR: the class \"" << rc->get_name() << "\" is direct superclass of class \"" << i->get_name() << "\".\n"
1531 : " The class is not in the list of generated classes, "
1532 : "it was not found among already generated headers "
1533 : "(search list is defined by the -I | --include-dirs parameter) and "
1534 0 : "it is not defined by user via -D | --user-defined-classes.\n";
1535 0 : error_num++;
1536 : }
1537 : }
1538 : }
1539 : }
1540 : }
1541 :
1542 0 : if (error_num != 0)
1543 : {
1544 0 : std::cerr << "\n*** " << error_num << (error_num == 1 ? " error was" : " errors were") << " found.\n\n";
1545 : return (EXIT_FAILURE);
1546 : }
1547 :
1548 0 : for (const auto& cl : generated_classes)
1549 : {
1550 0 : std::string name(alnum_name(cl->get_name()));
1551 :
1552 0 : std::string cpp_hdr_name = cpp_dir_name + "/" + name + ".hpp";
1553 0 : std::string cpp_src_name = cpp_dir_name + "/" + name + ".cpp";
1554 :
1555 0 : std::ofstream cpp_hdr_file(cpp_hdr_name.c_str());
1556 0 : std::ofstream cpp_src_file(cpp_src_name.c_str());
1557 :
1558 0 : if (!cpp_hdr_file)
1559 : {
1560 0 : std::cerr << "ERROR: can not create file \"" << cpp_hdr_name << "\"\n";
1561 : return (EXIT_FAILURE);
1562 : }
1563 :
1564 0 : if (!cpp_src_file)
1565 : {
1566 0 : std::cerr << "ERROR: can not create file \"" << cpp_src_name << "\"\n";
1567 : return (EXIT_FAILURE);
1568 : }
1569 :
1570 0 : gen_cpp_header_prologue(name, cpp_hdr_file, cpp_ns_name, cpp_hdr_dir);
1571 0 : gen_cpp_body_prologue(name, cpp_src_file, cpp_hdr_dir);
1572 :
1573 0 : gen_header(cl, cpp_hdr_file, cpp_ns_name, cpp_hdr_dir, cl_info);
1574 0 : gen_cpp_body(cl, cpp_src_file, cpp_ns_name, cpp_hdr_dir, cl_info);
1575 :
1576 0 : gen_cpp_header_epilogue(cpp_hdr_file);
1577 0 : }
1578 :
1579 : // generate dump applications
1580 :
1581 0 : {
1582 0 : struct ConfigurationImplementations
1583 : {
1584 : const char * name;
1585 : const char * header;
1586 : const char * class_name;
1587 : const char * header_prologue;
1588 : const char * main_function_prologue;
1589 0 : } confs[] =
1590 : {
1591 : { 0, "conffwk/Configuration.hpp", 0, "", "" } };
1592 :
1593 0 : for (unsigned int i = 0; i < sizeof(confs) / sizeof(ConfigurationImplementations); ++i)
1594 : {
1595 0 : std::string dump_name = cpp_dir_name + "/dump";
1596 0 : if (!cpp_ns_name.empty())
1597 : {
1598 0 : dump_name += '_';
1599 0 : dump_name += alnum_name(cpp_ns_name);
1600 : }
1601 0 : if (confs[i].name)
1602 : {
1603 0 : dump_name += '_';
1604 0 : dump_name += confs[i].name;
1605 : }
1606 0 : dump_name += ".cpp";
1607 :
1608 0 : std::ofstream dmp(dump_name.c_str());
1609 :
1610 0 : dmp.exceptions(std::ostream::failbit | std::ostream::badbit);
1611 :
1612 0 : if (dmp)
1613 : {
1614 0 : try
1615 : {
1616 0 : gen_dump_application(dmp, class_names, cpp_ns_name, cpp_hdr_dir, confs[i].header, confs[i].class_name, confs[i].header_prologue, confs[i].main_function_prologue);
1617 : }
1618 0 : catch (std::exception& ex)
1619 : {
1620 0 : std::cerr << "ERROR: can not create file \"" << dump_name << "\": " << ex.what() << std::endl;
1621 0 : }
1622 : }
1623 : else
1624 : {
1625 0 : std::cerr << "ERROR: can not create file \"" << dump_name << "\"\n";
1626 0 : return (EXIT_FAILURE);
1627 : }
1628 0 : }
1629 : }
1630 :
1631 : // generate info file
1632 :
1633 0 : {
1634 0 : std::ofstream info(info_file_name.c_str());
1635 :
1636 0 : if (info)
1637 : {
1638 0 : write_info_file(info, cpp_ns_name, cpp_hdr_dir, generated_classes);
1639 : }
1640 : else
1641 : {
1642 0 : std::cerr << "ERROR: can not create file \"" << info_file_name << "\"\n";
1643 0 : return (EXIT_FAILURE);
1644 : }
1645 0 : }
1646 :
1647 0 : }
1648 0 : catch (oks::exception & ex)
1649 : {
1650 0 : std::cerr << "Caught oks exception:\n" << ex << std::endl;
1651 0 : return (EXIT_FAILURE);
1652 0 : }
1653 0 : catch (std::exception & e)
1654 : {
1655 0 : std::cerr << "Caught standard C++ exception: " << e.what() << std::endl;
1656 0 : return (EXIT_FAILURE);
1657 0 : }
1658 0 : catch (...)
1659 : {
1660 0 : std::cerr << "Caught unknown exception" << std::endl;
1661 0 : return (EXIT_FAILURE);
1662 0 : }
1663 :
1664 0 : return (EXIT_SUCCESS);
1665 0 : }
1666 :
|