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