Fawkes API  Fawkes Development Version
cpp_generator.cpp
00001  
00002 /***************************************************************************
00003  *  cpp_generator.cpp - C++ Interface generator
00004  *
00005  *  Created: Thu Oct 12 02:01:27 2006
00006  *  Copyright  2006-2008  Tim Niemueller [www.niemueller.de]
00007  *
00008  ****************************************************************************/
00009 
00010 /*  This program is free software; you can redistribute it and/or modify
00011  *  it under the terms of the GNU General Public License as published by
00012  *  the Free Software Foundation; either version 2 of the License, or
00013  *  (at your option) any later version.
00014  *
00015  *  This program is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  *  GNU Library General Public License for more details.
00019  *
00020  *  Read the full text in the LICENSE.GPL file in the doc directory.
00021  */
00022 
00023 #include "cpp_generator.h"
00024 #include "exceptions.h"
00025 
00026 #include <utils/misc/string_conversions.h>
00027 
00028 #include <algorithm>
00029 #include <iostream>
00030 #include <vector>
00031 #include <time.h>
00032 #include <fstream>
00033 
00034 using namespace std;
00035 
00036 
00037 /** @class CppInterfaceGenerator <interfaces/generator/cpp_generator.h>
00038  * Generator that transforms input from the InterfaceParser into valid
00039  * C++ classes.
00040  */
00041 
00042 /** Constructor.
00043  * @param directory Directory where to create the files
00044  * @param interface_name name of the interface, should end with Interface
00045  * @param config_basename basename of the config without suffix
00046  * @param author author of interface
00047  * @param year year of copyright
00048  * @param creation_date user-supplied creation date of interface
00049  * @param data_comment comment in data block.
00050  * @param hash MD5 hash of the config file that was used to generate the interface
00051  * @param hash_size size in bytes of hash
00052  * @param constants constants
00053  * @param enum_constants constants defined as an enum
00054  * @param data_fields data fields of the interface
00055  * @param pseudo_maps pseudo maps of the interface
00056  * @param messages messages defined in the interface
00057  */
00058 CppInterfaceGenerator::CppInterfaceGenerator(std::string directory, std::string interface_name,
00059                                              std::string config_basename, std::string author,
00060                                              std::string year, std::string creation_date,
00061                                              std::string data_comment,
00062                                              const unsigned char *hash, size_t hash_size,
00063                                              const std::vector<InterfaceConstant> &constants,
00064                                              const std::vector<InterfaceEnumConstant> &enum_constants,
00065                                              const std::vector<InterfaceField> &data_fields,
00066                                              const std::vector<InterfacePseudoMap> &pseudo_maps,
00067                                              const std::vector<InterfaceMessage> &messages
00068                                              )
00069 {
00070   this->dir    = directory;
00071   if ( dir.find_last_of("/") != (dir.length() - 1) ) {
00072     dir += "/";
00073   }
00074   this->author = author;
00075   this->year   = year;
00076   this->creation_date = creation_date;
00077   this->data_comment  = data_comment;
00078   this->hash = hash;
00079   this->hash_size = hash_size;
00080   this->constants = constants;
00081   this->enum_constants = enum_constants;
00082   this->data_fields = data_fields;
00083   this->pseudo_maps = pseudo_maps;
00084   this->messages = messages;
00085 
00086   filename_cpp = config_basename + ".cpp";
00087   filename_h   = config_basename + ".h";
00088   filename_o   = config_basename + ".o";
00089 
00090   if ( interface_name.find("Interface", 0) == string::npos ) {
00091     // append Interface
00092     class_name = interface_name + "Interface";
00093   } else {
00094     class_name = interface_name;
00095   }
00096 
00097   deflector = "__INTERFACES_" + fawkes::StringConversions::to_upper(config_basename) + "_H_";
00098 }
00099 
00100 
00101 /** Destructor */
00102 CppInterfaceGenerator::~CppInterfaceGenerator()
00103 {
00104 }
00105 
00106 
00107 
00108 /** Write optimized struct.
00109  * Create struct, try align data well, sort fields:
00110  * 1. unsigned int
00111  * 2. int
00112  * 3. unsigned long int
00113  * 4. long int
00114  * 5. float
00115  * 6. double
00116  * 7. bool
00117  * 8. byte
00118  * 8. string
00119  * @param f file to write to
00120  * @param name name of struct
00121  * @param is indentation space
00122  * @param fields fields for struct
00123  */
00124 void
00125 CppInterfaceGenerator::write_struct(FILE *f, std::string name, std::string /* indent space */ is,
00126                                     std::vector<InterfaceField> fields)
00127 {
00128 
00129   //stable_sort(fields.begin(), fields.end());
00130 
00131   fprintf(f,
00132           "#pragma pack(push,4)\n"
00133           "%s/** Internal data storage, do NOT modify! */\n"
00134           "%stypedef struct {\n"
00135           "%s  int64_t timestamp_sec;  /**< Interface Unix timestamp, seconds */\n"
00136           "%s  int64_t timestamp_usec; /**< Interface Unix timestamp, micro-seconds */\n", is.c_str(), is.c_str(), is.c_str(), is.c_str());
00137 
00138   for (vector<InterfaceField>::iterator i = fields.begin(); i != fields.end(); ++i) {
00139     fprintf(f, "%s  %s %s", is.c_str(), (*i).getStructType().c_str(), (*i).getName().c_str());
00140     if ( (*i).getLength().length() > 0 ) {
00141       fprintf(f, "[%s]", (*i).getLength().c_str());
00142     }
00143     fprintf(f, "; /**< %s */\n", (*i).getComment().c_str());
00144   }
00145   
00146   fprintf(f, "%s} %s;\n"
00147           "#pragma pack(pop)\n\n", is.c_str(), name.c_str());
00148 }
00149 
00150 
00151 /** Write header to file.
00152  * @param f file to write to
00153  * @param filename name of file
00154  */
00155 void
00156 CppInterfaceGenerator::write_header(FILE *f, std::string filename)
00157 {
00158   fprintf(f,
00159           "\n/***************************************************************************\n"
00160           " *  %s - Fawkes BlackBoard Interface - %s\n"
00161           " *\n"
00162           "%s%s%s"
00163           " *  Templated created:   Thu Oct 12 10:49:19 2006\n"
00164           " *  Copyright  %s  %s\n"
00165           " *\n"
00166           " ****************************************************************************/\n\n"
00167           "/*  This program is free software; you can redistribute it and/or modify\n"
00168           " *  it under the terms of the GNU General Public License as published by\n"
00169           " *  the Free Software Foundation; either version 2 of the License, or\n"
00170           " *  (at your option) any later version. A runtime exception applies to\n"
00171           " *  this software (see LICENSE.GPL_WRE file mentioned below for details).\n"
00172           " *\n"
00173           " *  This program is distributed in the hope that it will be useful,\n"
00174           " *  but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
00175           " *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n"
00176           " *  GNU Library General Public License for more details.\n"
00177           " *\n"
00178           " *  Read the full text in the LICENSE.GPL_WRE file in the doc directory.\n"
00179           " */\n\n",
00180           filename.c_str(), class_name.c_str(),
00181           (creation_date.length() > 0 ) ? " *  Interface created: " : "",
00182           (creation_date.length() > 0 ) ? creation_date.c_str() : "",
00183           (creation_date.length() > 0 ) ? "\n" : "",
00184           year.c_str(), (author.length() > 0) ? author.c_str() : "AllemaniACs RoboCup Team"
00185           );
00186 }
00187 
00188 
00189 /** Write header deflector.
00190  * @param f file to write to
00191  */
00192 void
00193 CppInterfaceGenerator::write_deflector(FILE *f)
00194 {
00195   fprintf(f, "#ifndef %s\n", deflector.c_str());
00196   fprintf(f, "#define %s\n\n", deflector.c_str());
00197 }
00198 
00199 
00200 /** Write cpp file.
00201  * @param f file to write to
00202  */
00203 void
00204 CppInterfaceGenerator::write_cpp(FILE *f)
00205 {
00206   write_header(f, filename_cpp);
00207   fprintf(f,
00208           "#include <interfaces/%s>\n\n"
00209           "#include <core/exceptions/software.h>\n\n"
00210           "#include <cstring>\n"
00211           "#include <cstdlib>\n\n"
00212           "namespace fawkes {\n\n"
00213           "/** @class %s <interfaces/%s>\n"
00214           " * %s Fawkes BlackBoard Interface.\n"
00215           " * %s\n"
00216           " * @ingroup FawkesInterfaces\n"
00217           " */\n\n\n",
00218           filename_h.c_str(), class_name.c_str(), filename_h.c_str(),
00219           class_name.c_str(), data_comment.c_str());
00220   write_constants_cpp(f);
00221   write_ctor_dtor_cpp(f, class_name, "Interface", "", data_fields, messages);
00222   write_enum_constants_tostring_cpp(f);
00223   write_methods_cpp(f, class_name, class_name, data_fields, pseudo_maps, "");
00224   write_basemethods_cpp(f);
00225   write_messages_cpp(f);
00226 
00227   write_management_funcs_cpp(f);
00228 
00229   fprintf(f, "\n} // end namespace fawkes\n");
00230 }
00231 
00232 
00233 /** Write management functions.
00234  * @param f file to write to
00235  */
00236 void
00237 CppInterfaceGenerator::write_management_funcs_cpp(FILE *f)
00238 {
00239   fprintf(f,
00240           "/// @cond INTERNALS\n"
00241           "EXPORT_INTERFACE(%s)\n"
00242           "/// @endcond\n\n",
00243           class_name.c_str());
00244 }
00245 
00246 
00247 /** Write constants to cpp file.
00248  * @param f file to write to
00249  */
00250 void
00251 CppInterfaceGenerator::write_constants_cpp(FILE *f)
00252 {
00253   for ( vector<InterfaceConstant>::iterator i = constants.begin(); i != constants.end(); ++i) {
00254     const char *type_suffix = "";
00255     if (i->getType() == "uint32_t") {
00256       type_suffix = "u";
00257     }
00258     fprintf(f,
00259             "/** %s constant */\n"
00260             "const %s %s::%s = %s%s;\n",
00261             (*i).getName().c_str(),
00262             (*i).getType().c_str(),
00263             class_name.c_str(), i->getName().c_str(),
00264             i->getValue().c_str(), type_suffix);
00265   }
00266   fprintf(f, "\n");
00267 }
00268 
00269 
00270 /** Write enum constant tostring methods to cpp file.
00271  * @param f file to write to
00272  */
00273 void
00274 CppInterfaceGenerator::write_enum_constants_tostring_cpp(FILE *f)
00275 {
00276   for ( vector<InterfaceEnumConstant>::iterator i = enum_constants.begin(); i != enum_constants.end(); ++i) {
00277     fprintf(f,
00278             "/** Convert %s constant to string.\n"
00279             " * @param value value to convert to string\n"
00280             " * @return constant value as string.\n"
00281             " */\n"
00282             "const char *\n"
00283             "%s::tostring_%s(%s value) const\n"
00284             "{\n"
00285             "  switch (value) {\n",
00286             i->get_name().c_str(), class_name.c_str(), i->get_name().c_str(),
00287             i->get_name().c_str());
00288     vector<InterfaceEnumConstant::EnumItem> items = i->get_items();
00289     vector<InterfaceEnumConstant::EnumItem>::iterator j;
00290     for (j = items.begin(); j != items.end(); ++j) {
00291       fprintf(f, "  case %s: return \"%s\";\n",
00292               j->name.c_str(), j->name.c_str());
00293     }
00294     fprintf(f,
00295             "  default: return \"UNKNOWN\";\n"
00296             "  }\n"
00297             "}\n");
00298   }
00299 }
00300 
00301 /** Write constants to h file
00302  * @param f file to write to
00303  */
00304 void
00305 CppInterfaceGenerator::write_constants_h(FILE *f)
00306 {
00307   fprintf(f, "  /* constants */\n");
00308   for ( vector<InterfaceConstant>::iterator i = constants.begin(); i != constants.end(); ++i) {
00309     fprintf(f, "  static const %s %s;\n", (*i).getType().c_str(), (*i).getName().c_str());
00310   }
00311   fprintf(f, "\n");
00312 
00313   for ( vector<InterfaceEnumConstant>::iterator i = enum_constants.begin(); i != enum_constants.end(); ++i) {
00314     fprintf(f,
00315             "  /** %s */\n"
00316             "  typedef enum {\n",
00317             (*i).get_comment().c_str());
00318     vector<InterfaceEnumConstant::EnumItem> items = i->get_items();
00319     vector<InterfaceEnumConstant::EnumItem>::iterator j = items.begin();
00320     while (j != items.end()) {
00321       if (j->has_custom_value) {
00322         fprintf(f, "    %s = %i /**< %s */", j->name.c_str(),
00323                 j->custom_value, j->comment.c_str());
00324       } else {
00325         fprintf(f, "    %s /**< %s */", j->name.c_str(), j->comment.c_str());
00326       }
00327       ++j;
00328       if ( j != items.end() ) {
00329         fprintf(f, ",\n");
00330       } else {
00331         fprintf(f, "\n");
00332       }
00333     }
00334     fprintf(f, "  } %s;\n", (*i).get_name().c_str());
00335     fprintf(f, "  const char * tostring_%s(%s value) const;\n\n",
00336             i->get_name().c_str(), i->get_name().c_str());
00337   }
00338 }
00339 
00340 
00341 /** Write messages to h file.
00342  * @param f file to write to
00343  */
00344 void
00345 CppInterfaceGenerator::write_messages_h(FILE *f)
00346 {
00347   fprintf(f, "  /* messages */\n");
00348   for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
00349     fprintf(f, "  class %s : public Message\n"
00350             "  {\n", (*i).getName().c_str());
00351 
00352     fprintf(f, "   private:\n");
00353     write_struct(f, (*i).getName() + "_data_t", "    ", (*i).getFields());
00354     fprintf(f,
00355             "    %s_data_t *data;\n\n",
00356             (*i).getName().c_str());
00357 
00358     fprintf(f, "   public:\n");
00359     write_message_ctor_dtor_h(f, "    ", (*i).getName(), (*i).getFields());
00360     write_methods_h(f, "    ", (*i).getFields());
00361     write_message_clone_method_h(f, "    ");
00362     fprintf(f, "  };\n\n");
00363   }
00364   fprintf(f, "  virtual bool message_valid(const Message *message) const;\n");
00365 
00366 }
00367 
00368 
00369 /** Write messages to cpp file.
00370  * @param f file to write to
00371  */
00372 void
00373 CppInterfaceGenerator::write_messages_cpp(FILE *f)
00374 {
00375   fprintf(f, "/* =========== messages =========== */\n");
00376   for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
00377     fprintf(f,
00378             "/** @class %s::%s <interfaces/%s>\n"
00379             " * %s Fawkes BlackBoard Interface Message.\n"
00380             " * %s\n"
00381             " */\n\n\n",
00382             class_name.c_str(), (*i).getName().c_str(), filename_h.c_str(),
00383             (*i).getName().c_str(), (*i).getComment().c_str());
00384 
00385     write_message_ctor_dtor_cpp(f, (*i).getName(), "Message", class_name + "::",
00386                                 (*i).getFields());
00387     write_methods_cpp(f, class_name, (*i).getName(), (*i).getFields(), class_name + "::", false);
00388     write_message_clone_method_cpp(f, (class_name + "::" + (*i).getName()).c_str());
00389   }
00390   fprintf(f,
00391           "/** Check if message is valid and can be enqueued.\n"
00392           " * @param message Message to check\n"
00393           " * @return true if the message is valid, false otherwise.\n"
00394           " */\n"
00395           "bool\n"
00396           "%s::message_valid(const Message *message) const\n"
00397           "{\n", class_name.c_str());
00398   unsigned int n = 0;
00399   for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
00400     fprintf(f,
00401             "  const %s *m%u = dynamic_cast<const %s *>(message);\n"
00402             "  if ( m%u != NULL ) {\n"
00403             "    return true;\n"
00404             "  }\n",
00405             (*i).getName().c_str(), n, (*i).getName().c_str(), n);
00406     ++n;
00407   }
00408   fprintf(f,
00409           "  return false;\n"
00410           "}\n\n");
00411 }
00412 
00413 
00414 /** Write create_message() method to cpp file.
00415  * @param f file to write to
00416  */
00417 void
00418 CppInterfaceGenerator::write_create_message_method_cpp(FILE *f)
00419 {
00420   fprintf(f, "/* =========== message create =========== */\n");
00421   fprintf(f,
00422           "Message *\n"
00423           "%s::create_message(const char *type) const\n"
00424           "{\n", class_name.c_str());
00425 
00426   bool first = true;
00427   for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
00428     fprintf(f,
00429             "  %sif ( strncmp(\"%s\", type, __INTERFACE_MESSAGE_TYPE_SIZE) == 0 ) {\n"
00430             "    return new %s();\n",
00431             first ? "" : "} else ", i->getName().c_str(), i->getName().c_str());
00432     first = false;
00433   }
00434   if (first) {
00435     fprintf(f,
00436             "  throw UnknownTypeException(\"The given type '%%s' does not match any known \"\n"
00437             "                             \"message type for this interface type.\", type);\n"
00438             "}\n\n\n");
00439   } else {
00440     fprintf(f,
00441             "  } else {\n"
00442             "    throw UnknownTypeException(\"The given type '%%s' does not match any known \"\n"
00443             "                               \"message type for this interface type.\", type);\n"
00444             "  }\n"
00445             "}\n\n\n");
00446   }
00447 }
00448 
00449 
00450 /** Write copy_value() method to CPP file.
00451  * @param f file to write to
00452  */
00453 void
00454 CppInterfaceGenerator::write_copy_value_method_cpp(FILE *f)
00455 {
00456   fprintf(f,
00457           "/** Copy values from other interface.\n"
00458           " * @param other other interface to copy values from\n"
00459           " */\n"
00460           "void\n"
00461           "%s::copy_values(const Interface *other)\n"
00462           "{\n"
00463           "  const %s *oi = dynamic_cast<const %s *>(other);\n"
00464           "  if (oi == NULL) {\n"
00465           "    throw TypeMismatchException(\"Can only copy values from interface of same type (%%s vs. %%s)\",\n"
00466           "                                type(), other->type());\n"
00467           "  }\n"
00468           "  memcpy(data, oi->data, sizeof(%s_data_t));\n"
00469           "}\n\n",
00470           class_name.c_str(), class_name.c_str(), class_name.c_str(), class_name.c_str());
00471 }
00472 
00473 
00474 /** Write enum_tostring() method to CPP file.
00475  * @param f file to write to
00476  */
00477 void
00478 CppInterfaceGenerator::write_enum_tostring_method_cpp(FILE *f)
00479 {
00480   fprintf(f,
00481           "const char *\n"
00482           "%s::enum_tostring(const char *enumtype, int val) const\n"
00483           "{\n", class_name.c_str());
00484   for ( vector<InterfaceEnumConstant>::iterator i = enum_constants.begin(); i != enum_constants.end(); ++i) {
00485     fprintf(f,
00486             "  if (strcmp(enumtype, \"%s\") == 0) {\n"
00487             "    return tostring_%s((%s)val);\n"
00488             "  }\n",
00489             i->get_name().c_str(), i->get_name().c_str(), i->get_name().c_str());
00490   }
00491   fprintf(f,
00492           "  throw UnknownTypeException(\"Unknown enum type %%s\", enumtype);\n"
00493           "}\n\n");
00494 }
00495 
00496 
00497 /** Write base methods.
00498  * @param f file to write to
00499  */ 
00500 void
00501 CppInterfaceGenerator::write_basemethods_cpp(FILE *f)
00502 {
00503   write_create_message_method_cpp(f);
00504   write_copy_value_method_cpp(f);
00505   write_enum_tostring_method_cpp(f);
00506 }
00507 
00508 
00509 /** Write constructor and destructor to h file.
00510  * @param f file to write to
00511  * @param is indentation space
00512  * @param classname name of class
00513  */
00514 void
00515 CppInterfaceGenerator::write_ctor_dtor_h(FILE *f, std::string /* indent space */ is,
00516                                          std::string classname)
00517 {
00518   fprintf(f,
00519           "%s%s();\n"
00520           "%s~%s();\n\n",
00521           is.c_str(), classname.c_str(),
00522           is.c_str(), classname.c_str());
00523 }
00524 
00525 
00526 /** Write constructor and destructor for message to h file.
00527  * @param f file to write to
00528  * @param is indentation space
00529  * @param classname name of class
00530  * @param fields vector of data fields of message
00531  */
00532 void
00533 CppInterfaceGenerator::write_message_ctor_dtor_h(FILE *f, std::string /* indent space */ is,
00534                                                  std::string classname,
00535                                                  std::vector<InterfaceField> fields)
00536 {
00537   vector<InterfaceField>::iterator i;
00538 
00539   if ( fields.size() > 0 ) {
00540 
00541     fprintf(f, "%s%s(", is.c_str(), classname.c_str());
00542 
00543     i = fields.begin();
00544     while (i != fields.end()) {
00545       fprintf(f, "const %s ini_%s",
00546               (*i).getAccessType().c_str(), (*i).getName().c_str());
00547       ++i;
00548       if ( i != fields.end() ) {
00549         fprintf(f, ", ");
00550       }
00551     }
00552 
00553     fprintf(f, ");\n");
00554   }
00555 
00556   write_ctor_dtor_h(f, is, classname);
00557   fprintf(f, "%s%s(const %s *m);\n", is.c_str(), classname.c_str(), classname.c_str());
00558 
00559 }
00560 
00561 
00562 /** Write message clone method header.
00563  * @param f file to write to
00564  * @param is indentation space
00565  */
00566 void
00567 CppInterfaceGenerator::write_message_clone_method_h(FILE *f, std::string is)
00568 {
00569   fprintf(f, "%svirtual Message * clone() const;\n", is.c_str());
00570 }
00571 
00572 
00573 /** Write message clone method.
00574  * @param f file to write to
00575  * @param classname name of message class
00576  */
00577 void
00578 CppInterfaceGenerator::write_message_clone_method_cpp(FILE *f, std::string classname)
00579 {
00580   fprintf(f,
00581           "/** Clone this message.\n"
00582           " * Produces a message of the same type as this message and copies the\n"
00583           " * data to the new message.\n"
00584           " * @return clone of this message\n"
00585           " */\n"
00586           "Message *\n"
00587           "%s::clone() const\n"
00588           "{\n"
00589           "  return new %s(this);\n"
00590           "}\n", classname.c_str(), classname.c_str());
00591 }
00592 
00593 /** Write the add_fieldinfo() calls.
00594  * @param f file to write to
00595  * @param fields fields to write field info for
00596  */
00597 void
00598 CppInterfaceGenerator::write_add_fieldinfo_calls(FILE *f, std::vector<InterfaceField> &fields)
00599 {
00600   std::vector<InterfaceField>::iterator i;
00601   for (i = fields.begin(); i != fields.end(); ++i) {
00602     const char *type = "";
00603     const char *dataptr = "&";
00604     const char *enumtype = 0;
00605 
00606     if ( i->getType() == "bool" ) {
00607       type = "BOOL";
00608     } else if ( i->getType() == "int8" ) {
00609       type = "INT8";
00610     } else if ( i->getType() == "uint8" ) {
00611       type = "UINT8";
00612     } else if ( i->getType() == "int16" ) {
00613       type = "INT16";
00614     } else if ( i->getType() == "uint16" ) {
00615       type = "UINT16";
00616     } else if ( i->getType() == "int32" ) {
00617       type = "INT32";
00618     } else if ( i->getType() == "uint32" ) {
00619       type = "UINT32";
00620     } else if ( i->getType() == "int64" ) {
00621       type = "INT64";
00622     } else if ( i->getType() == "uint64" ) {
00623       type = "UINT64";
00624     } else if ( i->getType() == "byte" ) {
00625       type = "BYTE";
00626     } else if ( i->getType() == "float" ) {
00627       type = "FLOAT";
00628     } else if ( i->getType() == "double" ) {
00629       type = "DOUBLE";
00630     } else if ( i->getType() == "string" ) {
00631       type = "STRING";
00632       dataptr = "";
00633     } else {
00634       type = "ENUM";
00635       enumtype = i->getType().c_str();
00636     }
00637 
00638     fprintf(f, "  add_fieldinfo(IFT_%s, \"%s\", %u, %sdata->%s%s%s%s);\n",
00639             type, i->getName().c_str(),
00640             (i->getLengthValue() > 0) ? i->getLengthValue() : 1,
00641             dataptr, i->getName().c_str(),
00642             enumtype ? ", \"" : "",
00643             enumtype ? enumtype : "",
00644             enumtype ? "\"" : ""
00645             );
00646   }
00647 }
00648 
00649 
00650 /** Write constructor and destructor to cpp file.
00651  * @param f file to write to
00652  * @param classname name of class
00653  * @param super_class name of base class
00654  * @param inclusion_prefix Used if class is included in another class.
00655  * @param fields fields
00656  * @param messages messages
00657  */
00658 void
00659 CppInterfaceGenerator::write_ctor_dtor_cpp(FILE *f,
00660                                            std::string classname, std::string super_class,
00661                                            std::string inclusion_prefix,
00662                                            std::vector<InterfaceField> fields,
00663                                            std::vector<InterfaceMessage> messages)
00664 {
00665   fprintf(f,
00666           "/** Constructor */\n"
00667           "%s%s::%s() : %s()\n"
00668           "{\n",
00669           inclusion_prefix.c_str(), classname.c_str(),
00670           classname.c_str(), super_class.c_str());
00671 
00672   fprintf(f,
00673           "  data_size = sizeof(%s_data_t);\n"
00674           "  data_ptr  = malloc(data_size);\n"
00675           "  data      = (%s_data_t *)data_ptr;\n"
00676           "  data_ts   = (interface_data_ts_t *)data_ptr;\n"
00677           "  memset(data_ptr, 0, data_size);\n",
00678           classname.c_str(), classname.c_str());
00679 
00680   write_add_fieldinfo_calls(f, fields);
00681 
00682   for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
00683     fprintf(f, "  add_messageinfo(\"%s\");\n", i->getName().c_str());
00684   }
00685 
00686   fprintf(f, "  unsigned char tmp_hash[] = {");
00687   for (size_t st = 0; st < hash_size-1; ++st) {
00688     fprintf(f, "%#02x, ", hash[st]);
00689   }
00690   fprintf(f, "%#02x};\n", hash[hash_size-1]);
00691   fprintf(f, "  set_hash(tmp_hash);\n");
00692 
00693   fprintf(f,
00694           "}\n\n"
00695           "/** Destructor */\n"
00696           "%s%s::~%s()\n"
00697           "{\n"
00698           "  free(data_ptr);\n"
00699           "}\n",
00700           inclusion_prefix.c_str(), classname.c_str(), classname.c_str()
00701           );
00702 }
00703 
00704 
00705 /** Write constructor and destructor for message to cpp file.
00706  * @param f file to write to
00707  * @param classname name of class
00708  * @param super_class name of base class
00709  * @param inclusion_prefix Used if class is included in another class.
00710  * @param fields vector of data fields of message
00711  */
00712 void
00713 CppInterfaceGenerator::write_message_ctor_dtor_cpp(FILE *f,
00714                                                    std::string classname, std::string super_class,
00715                                                    std::string inclusion_prefix,
00716                                                    std::vector<InterfaceField> fields)
00717 {
00718   vector<InterfaceField>::iterator i;
00719 
00720   if ( fields.size() > 0 ) {
00721     fprintf(f,
00722             "/** Constructor with initial values.\n");
00723 
00724     for (i = fields.begin(); i != fields.end(); ++i) {
00725       fprintf(f, " * @param ini_%s initial value for %s\n",
00726               (*i).getName().c_str(), (*i).getName().c_str());
00727     }
00728 
00729     fprintf(f,
00730             " */\n"
00731             "%s%s::%s(",
00732             inclusion_prefix.c_str(), classname.c_str(), classname.c_str());
00733 
00734     i = fields.begin();
00735     while (i != fields.end()) {
00736       fprintf(f, "const %s ini_%s",
00737               (*i).getAccessType().c_str(), (*i).getName().c_str());
00738       ++i;
00739       if ( i != fields.end() ) {
00740         fprintf(f, ", ");
00741       }
00742     }
00743 
00744     fprintf(f,") : %s(\"%s\")\n"
00745             "{\n"
00746             "  data_size = sizeof(%s_data_t);\n"
00747             "  data_ptr  = malloc(data_size);\n"
00748             "  memset(data_ptr, 0, data_size);\n"
00749             "  data      = (%s_data_t *)data_ptr;\n"
00750             "  data_ts   = (message_data_ts_t *)data_ptr;\n",
00751             super_class.c_str(), classname.c_str(), classname.c_str(), classname.c_str());
00752     
00753     for (i = fields.begin(); i != fields.end(); ++i) {
00754       if ( (*i).getType() == "string" ) {
00755         fprintf(f, "  strncpy(data->%s, ini_%s, %s);\n",
00756                 (*i).getName().c_str(), (*i).getName().c_str(),
00757                 (*i).getLength().c_str());
00758       } else if (i->getLengthValue() > 1) {
00759         fprintf(f, "  memcpy(data->%s, ini_%s, sizeof(%s) * %s);\n",
00760                 i->getName().c_str(), i->getName().c_str(),
00761                 i->getPlainAccessType().c_str(), i->getLength().c_str());
00762 
00763 
00764       } else {
00765         fprintf(f, "  data->%s = ini_%s;\n",
00766                 (*i).getName().c_str(), (*i).getName().c_str());
00767       }
00768     }
00769 
00770     write_add_fieldinfo_calls(f, fields);
00771 
00772     fprintf(f, "}\n");
00773   }
00774 
00775   fprintf(f,
00776           "/** Constructor */\n"
00777           "%s%s::%s() : %s(\"%s\")\n"
00778           "{\n",
00779           inclusion_prefix.c_str(), classname.c_str(),
00780           classname.c_str(), super_class.c_str(), classname.c_str());
00781 
00782   fprintf(f,
00783           "  data_size = sizeof(%s_data_t);\n"
00784           "  data_ptr  = malloc(data_size);\n"
00785           "  memset(data_ptr, 0, data_size);\n"
00786           "  data      = (%s_data_t *)data_ptr;\n"
00787           "  data_ts   = (message_data_ts_t *)data_ptr;\n",
00788           classname.c_str(), classname.c_str());
00789 
00790   write_add_fieldinfo_calls(f, fields);
00791 
00792   fprintf(f,
00793           "}\n\n"
00794           "/** Destructor */\n"
00795           "%s%s::~%s()\n"
00796           "{\n"
00797           "  free(data_ptr);\n"
00798           "}\n\n",
00799           inclusion_prefix.c_str(), classname.c_str(), classname.c_str());
00800 
00801   fprintf(f,
00802           "/** Copy constructor.\n"
00803           " * @param m message to copy from\n"
00804           " */\n"
00805           "%s%s::%s(const %s *m) : %s(\"%s\")\n"
00806           "{\n",
00807           inclusion_prefix.c_str(), classname.c_str(), classname.c_str(),
00808           classname.c_str(), super_class.c_str(), classname.c_str());
00809 
00810   fprintf(f,
00811           "  data_size = m->data_size;\n"
00812           "  data_ptr  = malloc(data_size);\n"
00813           "  memcpy(data_ptr, m->data_ptr, data_size);\n"
00814           "  data      = (%s_data_t *)data_ptr;\n"
00815           "  data_ts   = (message_data_ts_t *)data_ptr;\n",
00816           classname.c_str());
00817 
00818 
00819   fprintf(f, "}\n\n");
00820 }
00821 
00822 
00823 /** Write methods to cpp file.
00824  * @param f file to write to
00825  * @param interface_classname name of the interface class
00826  * @param classname name of class (can be interface or message)
00827  * @param fields fields
00828  * @param inclusion_prefix used if class is included in another class.
00829  * @param write_data_changed if true writes code that sets the interface's
00830  * data_changed flag. Set to true for interface methods, false for message
00831  * methods.
00832  */
00833 void
00834 CppInterfaceGenerator::write_methods_cpp(FILE *f, std::string interface_classname,
00835                                          std::string classname,
00836                                          std::vector<InterfaceField> fields,
00837                                          std::string inclusion_prefix,
00838                                          bool write_data_changed)
00839 {
00840   fprintf(f, "/* Methods */\n");
00841   for (vector<InterfaceField>::iterator i = fields.begin(); i != fields.end(); ++i) {
00842     fprintf(f,
00843             "/** Get %s value.\n"
00844             " * %s\n"
00845             " * @return %s value\n"
00846             " */\n"
00847             "%s%s\n"
00848             "%s%s::%s%s() const\n"
00849             "{\n"
00850             "  return %sdata->%s;\n"
00851             "}\n\n",
00852             (*i).getName().c_str(),
00853             (*i).getComment().c_str(),
00854             (*i).getName().c_str(),
00855             (*i).isEnumType() ? (interface_classname + "::").c_str() : "",
00856             (*i).getAccessType().c_str(),
00857             inclusion_prefix.c_str(), classname.c_str(), ( ((*i).getType() == "bool" ) ? "is_" : ""), (*i).getName().c_str(),
00858             (*i).isEnumType() ? (std::string("(") + interface_classname + "::" +
00859                                  i->getAccessType() + ")").c_str() : "",
00860             (*i).getName().c_str() );
00861 
00862     if ( (i->getLengthValue() > 0) && (i->getType() != "string") ) {
00863       fprintf(f,
00864               "/** Get %s value at given index.\n"
00865               " * %s\n"
00866               " * @param index index of value\n"
00867               " * @return %s value\n"
00868               " * @exception Exception thrown if index is out of bounds\n"
00869               " */\n"
00870               "%s%s\n"
00871               "%s%s::%s%s(unsigned int index) const\n"
00872               "{\n"
00873               "  if (index > %s) {\n"
00874               "    throw Exception(\"Index value %%u out of bounds (0..%s)\", index);\n"
00875               "  }\n"
00876               "  return %sdata->%s[index];\n"
00877               "}\n\n",
00878               (*i).getName().c_str(),
00879               (*i).getComment().c_str(),
00880               (*i).getName().c_str(),
00881               (*i).isEnumType() ? (interface_classname + "::").c_str() : "",
00882               (*i).getPlainAccessType().c_str(),
00883               inclusion_prefix.c_str(), classname.c_str(),
00884               ( ((*i).getType() == "bool" ) ? "is_" : ""), (*i).getName().c_str(),
00885               i->getLength().c_str(), i->getLength().c_str(),
00886               (*i).isEnumType() ? (std::string("(") + interface_classname + "::" +
00887                                    i->getPlainAccessType() + ")").c_str() : "",
00888               (*i).getName().c_str() );
00889     }
00890 
00891     fprintf(f,
00892             "/** Get maximum length of %s value.\n"
00893             " * @return length of %s value, can be length of the array or number of \n"
00894             " * maximum number of characters for a string\n"
00895             " */\n"
00896             "size_t\n"
00897             "%s%s::maxlenof_%s() const\n"
00898             "{\n"
00899             "  return %s;\n"
00900             "}\n\n",
00901             i->getName().c_str(), i->getName().c_str(), inclusion_prefix.c_str(),
00902             classname.c_str(), i->getName().c_str(),
00903             i->getLengthValue() > 0 ? i->getLength().c_str() : "1" );
00904 
00905     fprintf(f,
00906             "/** Set %s value.\n"
00907             " * %s\n"
00908             " * @param new_%s new %s value\n"
00909             " */\n"
00910             "void\n"
00911             "%s%s::set_%s(const %s new_%s)\n"
00912             "{\n",
00913             (*i).getName().c_str(),
00914             (*i).getComment().c_str(),      
00915             (*i).getName().c_str(), (*i).getName().c_str(),
00916             inclusion_prefix.c_str(), classname.c_str(), (*i).getName().c_str(), (*i).getAccessType().c_str(), (*i).getName().c_str()
00917             );
00918     if ( (*i).getType() == "string" ) {
00919       fprintf(f,
00920               "  strncpy(data->%s, new_%s, sizeof(data->%s));\n",
00921               (*i).getName().c_str(), (*i).getName().c_str(), (*i).getName().c_str());
00922     } else if ( (*i).getLength() != "" ) {
00923       fprintf(f,
00924               "  memcpy(data->%s, new_%s, sizeof(%s) * %s);\n",
00925               (*i).getName().c_str(), (*i).getName().c_str(),
00926               (*i).getPlainAccessType().c_str(), (*i).getLength().c_str());
00927     } else {
00928       fprintf(f,
00929               "  data->%s = new_%s;\n",
00930               (*i).getName().c_str(), (*i).getName().c_str());
00931     }
00932     fprintf(f, "%s}\n\n", write_data_changed ? "  data_changed = true;\n" : "");
00933 
00934     if ( ((*i).getType() != "string") && ((*i).getLengthValue() > 0) ) {
00935       fprintf(f,
00936               "/** Set %s value at given index.\n"
00937               " * %s\n"
00938               " * @param new_%s new %s value\n"
00939               " * @param index index for of the value\n"
00940               " */\n"
00941               "void\n"
00942               "%s%s::set_%s(unsigned int index, const %s new_%s)\n"
00943               "{\n"
00944               "  if (index > %s) {\n"
00945               "    throw Exception(\"Index value %%u out of bounds (0..%s)\", index);\n"
00946               "  }\n"
00947               "  data->%s[index] = new_%s;\n"
00948               "%s"
00949               "}\n",
00950               (*i).getName().c_str(),
00951               (*i).getComment().c_str(),            
00952               (*i).getName().c_str(), (*i).getName().c_str(),
00953               inclusion_prefix.c_str(), classname.c_str(), (*i).getName().c_str(),
00954               (*i).getPlainAccessType().c_str(), i->getName().c_str(),
00955               i->getLength().c_str(), i->getLength().c_str(),
00956               i->getName().c_str(), i->getName().c_str(),
00957               write_data_changed ? "  data_changed = true;\n" : "");
00958     }
00959   }
00960 }
00961 
00962 
00963 /** Write methods to cpp file including pseudo maps.
00964  * @param f file to write to
00965  * @param interface_classname name of the interface class
00966  * @param classname name of class (can be interface or message)
00967  * @param fields fields
00968  * @param pseudo_maps pseudo maps
00969  * @param inclusion_prefix used if class is included in another class.
00970  */
00971 void
00972 CppInterfaceGenerator::write_methods_cpp(FILE *f, std::string interface_classname,
00973                                          std::string classname,
00974                                          std::vector<InterfaceField> fields,
00975                                          std::vector<InterfacePseudoMap> pseudo_maps,
00976                                          std::string inclusion_prefix)
00977 {
00978   write_methods_cpp(f, interface_classname, classname, fields,
00979                     inclusion_prefix, true);
00980 
00981   for (vector<InterfacePseudoMap>::iterator i = pseudo_maps.begin(); i != pseudo_maps.end(); ++i) {
00982     fprintf(f,
00983             "/** Get %s value.\n"
00984             " * %s\n"
00985             " * @param key key of the value\n"
00986             " * @return %s value\n"
00987             " */\n"
00988             "%s\n"
00989             "%s%s::%s(const %s key) const\n"
00990             "{\n",
00991             (*i).getName().c_str(),
00992             (*i).getComment().c_str(),
00993             (*i).getName().c_str(),
00994             (*i).getType().c_str(),
00995             inclusion_prefix.c_str(), classname.c_str(), (*i).getName().c_str(),
00996             (*i).getKeyType().c_str() );
00997 
00998     InterfacePseudoMap::RefList &reflist = i->getRefList();
00999     InterfacePseudoMap::RefList::iterator paref;
01000     bool first = true;
01001     for (paref = reflist.begin(); paref != reflist.end(); ++paref) {
01002       fprintf(f, "  %sif (key == %s) {\n"
01003                  "    return data->%s;\n",
01004                  first ? "" : "} else ",
01005               paref->second.c_str(), paref->first.c_str());
01006       first = false;
01007     }
01008     fprintf(f, "  } else {\n"
01009                "    throw Exception(\"Invalid key, cannot retrieve value\");\n"
01010                "  }\n"
01011                "}\n\n");
01012 
01013     fprintf(f,
01014             "/** Set %s value.\n"
01015             " * %s\n"
01016             " * @param key key of the value\n"
01017             " * @param new_value new value\n"
01018             " */\n"
01019             "void\n"
01020             "%s%s::set_%s(const %s key, const %s new_value)\n"
01021             "{\n",
01022             (*i).getName().c_str(),
01023             (*i).getComment().c_str(),      
01024             inclusion_prefix.c_str(), classname.c_str(), (*i).getName().c_str(),
01025             (*i).getKeyType().c_str(), (*i).getType().c_str());
01026 
01027     first = true;
01028     for (paref = reflist.begin(); paref != reflist.end(); ++paref) {
01029       fprintf(f, "  %sif (key == %s) {\n"
01030                  "    data->%s = new_value;\n",
01031                  first ? "" : "} else ",
01032               paref->second.c_str(), paref->first.c_str());
01033       first = false;
01034     }
01035 
01036     fprintf(f, "  }\n"
01037                "}\n\n");
01038   }
01039 }
01040 
01041 
01042 
01043 /** Write methods to h file.
01044  * @param f file to write to
01045  * @param is indentation space.
01046  * @param fields fields to write accessor methods for.
01047  */
01048 void
01049 CppInterfaceGenerator::write_methods_h(FILE *f, std::string /* indent space */ is,
01050                                        std::vector<InterfaceField> fields)
01051 {
01052   fprintf(f, "%s/* Methods */\n", is.c_str());
01053   for (vector<InterfaceField>::iterator i = fields.begin(); i != fields.end(); ++i) {
01054     fprintf(f,
01055             "%s%s %s%s() const;\n",
01056             is.c_str(), (*i).getAccessType().c_str(),
01057             ( ((*i).getType() == "bool" ) ? "is_" : ""),
01058             (*i).getName().c_str());
01059 
01060     if ((i->getLengthValue() > 0) && (i->getType() != "string")) {
01061       fprintf(f,
01062               "%s%s %s%s(unsigned int index) const;\n"
01063               "%svoid set_%s(unsigned int index, const %s new_%s);\n",
01064               is.c_str(), i->getPlainAccessType().c_str(),
01065               ( ((*i).getType() == "bool" ) ? "is_" : ""),
01066               (*i).getName().c_str(),
01067               is.c_str(), (*i).getName().c_str(),
01068               i->getPlainAccessType().c_str(), i->getName().c_str());
01069     }
01070 
01071     fprintf(f,
01072             "%svoid set_%s(const %s new_%s);\n"
01073             "%ssize_t maxlenof_%s() const;\n",
01074             is.c_str(), (*i).getName().c_str(),
01075             i->getAccessType().c_str(), i->getName().c_str(),
01076             is.c_str(), i->getName().c_str()
01077             );
01078   }
01079 }
01080 
01081 
01082 /** Write methods to h file.
01083  * @param f file to write to
01084  * @param is indentation space.
01085  * @param fields fields to write accessor methods for.
01086  * @param pseudo_maps pseudo maps
01087  */
01088 void
01089 CppInterfaceGenerator::write_methods_h(FILE *f, std::string /* indent space */ is,
01090                                        std::vector<InterfaceField> fields,
01091                                        std::vector<InterfacePseudoMap> pseudo_maps)
01092 {
01093   write_methods_h(f, is, fields);
01094 
01095   for (vector<InterfacePseudoMap>::iterator i = pseudo_maps.begin(); i != pseudo_maps.end(); ++i) {
01096     fprintf(f,
01097             "%s%s %s(%s key) const;\n"
01098             "%svoid set_%s(const %s key, const %s new_value);\n",
01099             is.c_str(), (*i).getType().c_str(),
01100             (*i).getName().c_str(), (*i).getKeyType().c_str(),
01101             is.c_str(), (*i).getName().c_str(),
01102             i->getKeyType().c_str(), i->getType().c_str());
01103   }
01104 }
01105 
01106 
01107 /** Write base methods header entries.
01108  * @param f file to write to
01109  * @param is indentation string
01110  */
01111 void
01112 CppInterfaceGenerator::write_basemethods_h(FILE *f, std::string is)
01113 {
01114   fprintf(f,
01115           "%svirtual Message * create_message(const char *type) const;\n\n"
01116           "%svirtual void copy_values(const Interface *other);\n"
01117           "%svirtual const char * enum_tostring(const char *enumtype, int val) const;\n",
01118           is.c_str(), is.c_str(), is.c_str());
01119 }
01120 
01121 /** Write h file.
01122  * @param f file to write to
01123  */
01124 void
01125 CppInterfaceGenerator::write_h(FILE *f)
01126 {
01127   write_header(f, filename_h);
01128   write_deflector(f);
01129 
01130   fprintf(f,
01131           "#include <interface/interface.h>\n"
01132           "#include <interface/message.h>\n"
01133           "#include <interface/field_iterator.h>\n\n"
01134           "namespace fawkes {\n\n"
01135           "class %s : public Interface\n"
01136           "{\n"
01137           " /// @cond INTERNALS\n"
01138           " INTERFACE_MGMT_FRIENDS(%s)\n"
01139           " /// @endcond\n"
01140           " public:\n",
01141           class_name.c_str(),
01142           class_name.c_str());
01143 
01144   write_constants_h(f);
01145 
01146   fprintf(f, " private:\n");
01147 
01148   write_struct(f, class_name + "_data_t", "  ", data_fields);
01149 
01150   fprintf(f, "  %s_data_t *data;\n"
01151           "\n public:\n", class_name.c_str());
01152 
01153   write_messages_h(f);
01154   fprintf(f, " private:\n");
01155   write_ctor_dtor_h(f, "  ", class_name);
01156   fprintf(f, " public:\n");
01157   write_methods_h(f, "  ", data_fields, pseudo_maps);
01158   write_basemethods_h(f, "  ");
01159   fprintf(f, "\n};\n\n} // end namespace fawkes\n\n#endif\n");
01160 }
01161 
01162 
01163 /** Generator cpp and h files.
01164  */
01165 void
01166 CppInterfaceGenerator::generate()
01167 {
01168   char timestring[26]; // 26 is mentioned in man asctime_r
01169   struct tm timestruct;
01170   time_t t = time(NULL);
01171   localtime_r(&t, &timestruct);
01172   asctime_r(&timestruct, timestring);
01173   gendate = timestring;
01174 
01175   FILE *cpp;
01176   FILE *h;
01177 
01178   cpp = fopen(string(dir + filename_cpp).c_str(), "w");
01179   h   = fopen(string(dir + filename_h).c_str(), "w");
01180 
01181   if ( cpp == NULL ) {
01182     printf("Cannot open cpp file %s%s\n", dir.c_str(), filename_cpp.c_str());
01183   }
01184   if ( h == NULL ) {
01185     printf("Cannot open h file %s%s\n", dir.c_str(), filename_h.c_str());
01186   }
01187   
01188   write_cpp(cpp);
01189   write_h(h);
01190 
01191   fclose(cpp);
01192   fclose(h);
01193 }