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