LCOV - code coverage report
Current view: top level - oksdalgen/apps - oksdalgen.cxx (source / functions) Coverage Total Hit
Test: code.result Lines: 0.0 % 671 0
Test Date: 2026-10-11 15:05:20 Functions: 0.0 % 12 0

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

Generated by: LCOV version 2.0-1