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