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