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