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->getName().c_str(), class_name.c_str(), i->getName().c_str(),
00287             i->getName().c_str());
00288     vector< pair<string,string> > items = (*i).getItems();
00289     vector< pair<string,string> >::iterator j;
00290     for (j = items.begin(); j != items.end(); ++j) {
00291       fprintf(f, "  case %s: return \"%s\";\n",
00292               j->first.c_str(), j->first.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).getComment().c_str());
00318     vector< pair<string,string> > items = (*i).getItems();
00319     vector< pair<string,string> >::iterator j = items.begin();
00320     while (j != items.end()) {
00321       fprintf(f, "    %s /**< %s */", (*j).first.c_str(), (*j).second.c_str());
00322       ++j;
00323       if ( j != items.end() ) {
00324         fprintf(f, ",\n");
00325       } else {
00326         fprintf(f, "\n");
00327       }
00328     }
00329     fprintf(f, "  } %s;\n", (*i).getName().c_str());
00330     fprintf(f, "  const char * tostring_%s(%s value) const;\n\n",
00331             i->getName().c_str(), i->getName().c_str());
00332   }
00333 }
00334 
00335 
00336 /** Write messages to h file.
00337  * @param f file to write to
00338  */
00339 void
00340 CppInterfaceGenerator::write_messages_h(FILE *f)
00341 {
00342   fprintf(f, "  /* messages */\n");
00343   for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
00344     fprintf(f, "  class %s : public Message\n"
00345             "  {\n", (*i).getName().c_str());
00346 
00347     fprintf(f, "   private:\n");
00348     write_struct(f, (*i).getName() + "_data_t", "    ", (*i).getFields());
00349     fprintf(f,
00350             "    %s_data_t *data;\n\n",
00351             (*i).getName().c_str());
00352 
00353     fprintf(f, "   public:\n");
00354     write_message_ctor_dtor_h(f, "    ", (*i).getName(), (*i).getFields());
00355     write_methods_h(f, "    ", (*i).getFields());
00356     write_message_clone_method_h(f, "    ");
00357     fprintf(f, "  };\n\n");
00358   }
00359   fprintf(f, "  virtual bool message_valid(const Message *message) const;\n");
00360 
00361 }
00362 
00363 
00364 /** Write messages to cpp file.
00365  * @param f file to write to
00366  */
00367 void
00368 CppInterfaceGenerator::write_messages_cpp(FILE *f)
00369 {
00370   fprintf(f, "/* =========== messages =========== */\n");
00371   for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
00372     fprintf(f,
00373             "/** @class %s::%s <interfaces/%s>\n"
00374             " * %s Fawkes BlackBoard Interface Message.\n"
00375             " * %s\n"
00376             " */\n\n\n",
00377             class_name.c_str(), (*i).getName().c_str(), filename_h.c_str(),
00378             (*i).getName().c_str(), (*i).getComment().c_str());
00379 
00380     write_message_ctor_dtor_cpp(f, (*i).getName(), "Message", class_name + "::",
00381                                 (*i).getFields());
00382     write_methods_cpp(f, class_name, (*i).getName(), (*i).getFields(), class_name + "::", false);
00383     write_message_clone_method_cpp(f, (class_name + "::" + (*i).getName()).c_str());
00384   }
00385   fprintf(f,
00386           "/** Check if message is valid and can be enqueued.\n"
00387           " * @param message Message to check\n"
00388           " * @return true if the message is valid, false otherwise.\n"
00389           " */\n"
00390           "bool\n"
00391           "%s::message_valid(const Message *message) const\n"
00392           "{\n", class_name.c_str());
00393   unsigned int n = 0;
00394   for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
00395     fprintf(f,
00396             "  const %s *m%u = dynamic_cast<const %s *>(message);\n"
00397             "  if ( m%u != NULL ) {\n"
00398             "    return true;\n"
00399             "  }\n",
00400             (*i).getName().c_str(), n, (*i).getName().c_str(), n);
00401     ++n;
00402   }
00403   fprintf(f,
00404           "  return false;\n"
00405           "}\n\n");
00406 }
00407 
00408 
00409 /** Write create_message() method to cpp file.
00410  * @param f file to write to
00411  */
00412 void
00413 CppInterfaceGenerator::write_create_message_method_cpp(FILE *f)
00414 {
00415   fprintf(f, "/* =========== message create =========== */\n");
00416   fprintf(f,
00417           "Message *\n"
00418           "%s::create_message(const char *type) const\n"
00419           "{\n", class_name.c_str());
00420 
00421   bool first = true;
00422   for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
00423     fprintf(f,
00424             "  %sif ( strncmp(\"%s\", type, __INTERFACE_MESSAGE_TYPE_SIZE) == 0 ) {\n"
00425             "    return new %s();\n",
00426             first ? "" : "} else ", i->getName().c_str(), i->getName().c_str());
00427     first = false;
00428   }
00429   if (first) {
00430     fprintf(f,
00431             "  throw UnknownTypeException(\"The given type '%%s' does not match any known \"\n"
00432             "                             \"message type for this interface type.\", type);\n"
00433             "}\n\n\n");
00434   } else {
00435     fprintf(f,
00436             "  } else {\n"
00437             "    throw UnknownTypeException(\"The given type '%%s' does not match any known \"\n"
00438             "                               \"message type for this interface type.\", type);\n"
00439             "  }\n"
00440             "}\n\n\n");
00441   }
00442 }
00443 
00444 
00445 /** Write copy_value() method to CPP file.
00446  * @param f file to write to
00447  */
00448 void
00449 CppInterfaceGenerator::write_copy_value_method_cpp(FILE *f)
00450 {
00451   fprintf(f,
00452           "/** Copy values from other interface.\n"
00453           " * @param other other interface to copy values from\n"
00454           " */\n"
00455           "void\n"
00456           "%s::copy_values(const Interface *other)\n"
00457           "{\n"
00458           "  const %s *oi = dynamic_cast<const %s *>(other);\n"
00459           "  if (oi == NULL) {\n"
00460           "    throw TypeMismatchException(\"Can only copy values from interface of same type (%%s vs. %%s)\",\n"
00461           "                                type(), other->type());\n"
00462           "  }\n"
00463           "  memcpy(data, oi->data, sizeof(%s_data_t));\n"
00464           "}\n\n",
00465           class_name.c_str(), class_name.c_str(), class_name.c_str(), class_name.c_str());
00466 }
00467 
00468 
00469 /** Write enum_tostring() method to CPP file.
00470  * @param f file to write to
00471  */
00472 void
00473 CppInterfaceGenerator::write_enum_tostring_method_cpp(FILE *f)
00474 {
00475   fprintf(f,
00476           "const char *\n"
00477           "%s::enum_tostring(const char *enumtype, int val) const\n"
00478           "{\n", class_name.c_str());
00479   for ( vector<InterfaceEnumConstant>::iterator i = enum_constants.begin(); i != enum_constants.end(); ++i) {
00480     fprintf(f,
00481             "  if (strcmp(enumtype, \"%s\") == 0) {\n"
00482             "    return tostring_%s((%s)val);\n"
00483             "  }\n",
00484             i->getName().c_str(), i->getName().c_str(), i->getName().c_str());
00485   }
00486   fprintf(f,
00487           "  throw UnknownTypeException(\"Unknown enum type %%s\", enumtype);\n"
00488           "}\n\n");
00489 }
00490 
00491 
00492 /** Write base methods.
00493  * @param f file to write to
00494  */ 
00495 void
00496 CppInterfaceGenerator::write_basemethods_cpp(FILE *f)
00497 {
00498   write_create_message_method_cpp(f);
00499   write_copy_value_method_cpp(f);
00500   write_enum_tostring_method_cpp(f);
00501 }
00502 
00503 
00504 /** Write constructor and destructor to h file.
00505  * @param f file to write to
00506  * @param is indentation space
00507  * @param classname name of class
00508  */
00509 void
00510 CppInterfaceGenerator::write_ctor_dtor_h(FILE *f, std::string /* indent space */ is,
00511                                          std::string classname)
00512 {
00513   fprintf(f,
00514           "%s%s();\n"
00515           "%s~%s();\n\n",
00516           is.c_str(), classname.c_str(),
00517           is.c_str(), classname.c_str());
00518 }
00519 
00520 
00521 /** Write constructor and destructor for message to h file.
00522  * @param f file to write to
00523  * @param is indentation space
00524  * @param classname name of class
00525  * @param fields vector of data fields of message
00526  */
00527 void
00528 CppInterfaceGenerator::write_message_ctor_dtor_h(FILE *f, std::string /* indent space */ is,
00529                                                  std::string classname,
00530                                                  std::vector<InterfaceField> fields)
00531 {
00532   vector<InterfaceField>::iterator i;
00533 
00534   if ( fields.size() > 0 ) {
00535 
00536     fprintf(f, "%s%s(", is.c_str(), classname.c_str());
00537 
00538     i = fields.begin();
00539     while (i != fields.end()) {
00540       fprintf(f, "const %s ini_%s",
00541               (*i).getAccessType().c_str(), (*i).getName().c_str());
00542       ++i;
00543       if ( i != fields.end() ) {
00544         fprintf(f, ", ");
00545       }
00546     }
00547 
00548     fprintf(f, ");\n");
00549   }
00550 
00551   write_ctor_dtor_h(f, is, classname);
00552   fprintf(f, "%s%s(const %s *m);\n", is.c_str(), classname.c_str(), classname.c_str());
00553 
00554 }
00555 
00556 
00557 /** Write message clone method header.
00558  * @param f file to write to
00559  * @param is indentation space
00560  */
00561 void
00562 CppInterfaceGenerator::write_message_clone_method_h(FILE *f, std::string is)
00563 {
00564   fprintf(f, "%svirtual Message * clone() const;\n", is.c_str());
00565 }
00566 
00567 
00568 /** Write message clone method.
00569  * @param f file to write to
00570  * @param classname name of message class
00571  */
00572 void
00573 CppInterfaceGenerator::write_message_clone_method_cpp(FILE *f, std::string classname)
00574 {
00575   fprintf(f,
00576           "/** Clone this message.\n"
00577           " * Produces a message of the same type as this message and copies the\n"
00578           " * data to the new message.\n"
00579           " * @return clone of this message\n"
00580           " */\n"
00581           "Message *\n"
00582           "%s::clone() const\n"
00583           "{\n"
00584           "  return new %s(this);\n"
00585           "}\n", classname.c_str(), classname.c_str());
00586 }
00587 
00588 /** Write the add_fieldinfo() calls.
00589  * @param f file to write to
00590  * @param fields fields to write field info for
00591  */
00592 void
00593 CppInterfaceGenerator::write_add_fieldinfo_calls(FILE *f, std::vector<InterfaceField> &fields)
00594 {
00595   std::vector<InterfaceField>::iterator i;
00596   for (i = fields.begin(); i != fields.end(); ++i) {
00597     const char *type = "";
00598     const char *dataptr = "&";
00599     const char *enumtype = 0;
00600 
00601     if ( i->getType() == "bool" ) {
00602       type = "BOOL";
00603     } else if ( i->getType() == "int8" ) {
00604       type = "INT8";
00605     } else if ( i->getType() == "uint8" ) {
00606       type = "UINT8";
00607     } else if ( i->getType() == "int16" ) {
00608       type = "INT16";
00609     } else if ( i->getType() == "uint16" ) {
00610       type = "UINT16";
00611     } else if ( i->getType() == "int32" ) {
00612       type = "INT32";
00613     } else if ( i->getType() == "uint32" ) {
00614       type = "UINT32";
00615     } else if ( i->getType() == "int64" ) {
00616       type = "INT64";
00617     } else if ( i->getType() == "uint64" ) {
00618       type = "UINT64";
00619     } else if ( i->getType() == "byte" ) {
00620       type = "BYTE";
00621     } else if ( i->getType() == "float" ) {
00622       type = "FLOAT";
00623     } else if ( i->getType() == "string" ) {
00624       type = "STRING";
00625       dataptr = "";
00626     } else {
00627       type = "ENUM";
00628       enumtype = i->getType().c_str();
00629     }
00630 
00631     fprintf(f, "  add_fieldinfo(IFT_%s, \"%s\", %u, %sdata->%s%s%s%s);\n",
00632             type, i->getName().c_str(),
00633             (i->getLengthValue() > 0) ? i->getLengthValue() : 1,
00634             dataptr, i->getName().c_str(),
00635             enumtype ? ", \"" : "",
00636             enumtype ? enumtype : "",
00637             enumtype ? "\"" : ""
00638             );
00639   }
00640 }
00641 
00642 
00643 /** Write constructor and destructor to cpp file.
00644  * @param f file to write to
00645  * @param classname name of class
00646  * @param super_class name of base class
00647  * @param inclusion_prefix Used if class is included in another class.
00648  * @param fields fields
00649  * @param messages messages
00650  */
00651 void
00652 CppInterfaceGenerator::write_ctor_dtor_cpp(FILE *f,
00653                                            std::string classname, std::string super_class,
00654                                            std::string inclusion_prefix,
00655                                            std::vector<InterfaceField> fields,
00656                                            std::vector<InterfaceMessage> messages)
00657 {
00658   fprintf(f,
00659           "/** Constructor */\n"
00660           "%s%s::%s() : %s()\n"
00661           "{\n",
00662           inclusion_prefix.c_str(), classname.c_str(),
00663           classname.c_str(), super_class.c_str());
00664 
00665   fprintf(f,
00666           "  data_size = sizeof(%s_data_t);\n"
00667           "  data_ptr  = malloc(data_size);\n"
00668           "  data      = (%s_data_t *)data_ptr;\n"
00669           "  data_ts   = (interface_data_ts_t *)data_ptr;\n"
00670           "  memset(data_ptr, 0, data_size);\n",
00671           classname.c_str(), classname.c_str());
00672 
00673   write_add_fieldinfo_calls(f, fields);
00674 
00675   for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
00676     fprintf(f, "  add_messageinfo(\"%s\");\n", i->getName().c_str());
00677   }
00678 
00679   fprintf(f, "  unsigned char tmp_hash[] = {");
00680   for (size_t st = 0; st < hash_size-1; ++st) {
00681     fprintf(f, "%#02x, ", hash[st]);
00682   }
00683   fprintf(f, "%#02x};\n", hash[hash_size-1]);
00684   fprintf(f, "  set_hash(tmp_hash);\n");
00685 
00686   fprintf(f,
00687           "}\n\n"
00688           "/** Destructor */\n"
00689           "%s%s::~%s()\n"
00690           "{\n"
00691           "  free(data_ptr);\n"
00692           "}\n",
00693           inclusion_prefix.c_str(), classname.c_str(), classname.c_str()
00694           );
00695 }
00696 
00697 
00698 /** Write constructor and destructor for message to cpp file.
00699  * @param f file to write to
00700  * @param classname name of class
00701  * @param super_class name of base class
00702  * @param inclusion_prefix Used if class is included in another class.
00703  * @param fields vector of data fields of message
00704  */
00705 void
00706 CppInterfaceGenerator::write_message_ctor_dtor_cpp(FILE *f,
00707                                                    std::string classname, std::string super_class,
00708                                                    std::string inclusion_prefix,
00709                                                    std::vector<InterfaceField> fields)
00710 {
00711   vector<InterfaceField>::iterator i;
00712 
00713   if ( fields.size() > 0 ) {
00714     fprintf(f,
00715             "/** Constructor with initial values.\n");
00716 
00717     for (i = fields.begin(); i != fields.end(); ++i) {
00718       fprintf(f, " * @param ini_%s initial value for %s\n",
00719               (*i).getName().c_str(), (*i).getName().c_str());
00720     }
00721 
00722     fprintf(f,
00723             " */\n"
00724             "%s%s::%s(",
00725             inclusion_prefix.c_str(), classname.c_str(), classname.c_str());
00726 
00727     i = fields.begin();
00728     while (i != fields.end()) {
00729       fprintf(f, "const %s ini_%s",
00730               (*i).getAccessType().c_str(), (*i).getName().c_str());
00731       ++i;
00732       if ( i != fields.end() ) {
00733         fprintf(f, ", ");
00734       }
00735     }
00736 
00737     fprintf(f,") : %s(\"%s\")\n"
00738             "{\n"
00739             "  data_size = sizeof(%s_data_t);\n"
00740             "  data_ptr  = malloc(data_size);\n"
00741             "  memset(data_ptr, 0, data_size);\n"
00742             "  data      = (%s_data_t *)data_ptr;\n"
00743             "  data_ts   = (message_data_ts_t *)data_ptr;\n",
00744             super_class.c_str(), classname.c_str(), classname.c_str(), classname.c_str());
00745     
00746     for (i = fields.begin(); i != fields.end(); ++i) {
00747       if ( (*i).getType() == "string" ) {
00748         fprintf(f, "  strncpy(data->%s, ini_%s, %s);\n",
00749                 (*i).getName().c_str(), (*i).getName().c_str(),
00750                 (*i).getLength().c_str());
00751       } else if (i->getLengthValue() > 1) {
00752         fprintf(f, "  memcpy(data->%s, ini_%s, sizeof(%s) * %s);\n",
00753                 i->getName().c_str(), i->getName().c_str(),
00754                 i->getPlainAccessType().c_str(), i->getLength().c_str());
00755 
00756 
00757       } else {
00758         fprintf(f, "  data->%s = ini_%s;\n",
00759                 (*i).getName().c_str(), (*i).getName().c_str());
00760       }
00761     }
00762 
00763     write_add_fieldinfo_calls(f, fields);
00764 
00765     fprintf(f, "}\n");
00766   }
00767 
00768   fprintf(f,
00769           "/** Constructor */\n"
00770           "%s%s::%s() : %s(\"%s\")\n"
00771           "{\n",
00772           inclusion_prefix.c_str(), classname.c_str(),
00773           classname.c_str(), super_class.c_str(), classname.c_str());
00774 
00775   fprintf(f,
00776           "  data_size = sizeof(%s_data_t);\n"
00777           "  data_ptr  = malloc(data_size);\n"
00778           "  memset(data_ptr, 0, data_size);\n"
00779           "  data      = (%s_data_t *)data_ptr;\n"
00780           "  data_ts   = (message_data_ts_t *)data_ptr;\n",
00781           classname.c_str(), classname.c_str());
00782 
00783   write_add_fieldinfo_calls(f, fields);
00784 
00785   fprintf(f,
00786           "}\n\n"
00787           "/** Destructor */\n"
00788           "%s%s::~%s()\n"
00789           "{\n"
00790           "  free(data_ptr);\n"
00791           "}\n\n",
00792           inclusion_prefix.c_str(), classname.c_str(), classname.c_str());
00793 
00794   fprintf(f,
00795           "/** Copy constructor.\n"
00796           " * @param m message to copy from\n"
00797           " */\n"
00798           "%s%s::%s(const %s *m) : %s(\"%s\")\n"
00799           "{\n",
00800           inclusion_prefix.c_str(), classname.c_str(), classname.c_str(),
00801           classname.c_str(), super_class.c_str(), classname.c_str());
00802 
00803   fprintf(f,
00804           "  data_size = m->data_size;\n"
00805           "  data_ptr  = malloc(data_size);\n"
00806           "  memcpy(data_ptr, m->data_ptr, data_size);\n"
00807           "  data      = (%s_data_t *)data_ptr;\n"
00808           "  data_ts   = (message_data_ts_t *)data_ptr;\n",
00809           classname.c_str());
00810 
00811 
00812   fprintf(f, "}\n\n");
00813 }
00814 
00815 
00816 /** Write methods to cpp file.
00817  * @param f file to write to
00818  * @param interface_classname name of the interface class
00819  * @param classname name of class (can be interface or message)
00820  * @param fields fields
00821  * @param inclusion_prefix used if class is included in another class.
00822  * @param write_data_changed if true writes code that sets the interface's
00823  * data_changed flag. Set to true for interface methods, false for message
00824  * methods.
00825  */
00826 void
00827 CppInterfaceGenerator::write_methods_cpp(FILE *f, std::string interface_classname,
00828                                          std::string classname,
00829                                          std::vector<InterfaceField> fields,
00830                                          std::string inclusion_prefix,
00831                                          bool write_data_changed)
00832 {
00833   fprintf(f, "/* Methods */\n");
00834   for (vector<InterfaceField>::iterator i = fields.begin(); i != fields.end(); ++i) {
00835     fprintf(f,
00836             "/** Get %s value.\n"
00837             " * %s\n"
00838             " * @return %s value\n"
00839             " */\n"
00840             "%s%s\n"
00841             "%s%s::%s%s() const\n"
00842             "{\n"
00843             "  return data->%s;\n"
00844             "}\n\n",
00845             (*i).getName().c_str(),
00846             (*i).getComment().c_str(),
00847             (*i).getName().c_str(),
00848             (*i).isEnumType() ? (interface_classname + "::").c_str() : "",
00849             (*i).getAccessType().c_str(),
00850             inclusion_prefix.c_str(), classname.c_str(), ( ((*i).getType() == "bool" ) ? "is_" : ""), (*i).getName().c_str(),
00851             (*i).getName().c_str() );
00852 
00853     if ( (i->getLengthValue() > 0) && (i->getType() != "string") ) {
00854       fprintf(f,
00855               "/** Get %s value at given index.\n"
00856               " * %s\n"
00857               " * @param index index of value\n"
00858               " * @return %s value\n"
00859               " * @exception Exception thrown if index is out of bounds\n"
00860               " */\n"
00861               "%s%s\n"
00862               "%s%s::%s%s(unsigned int index) const\n"
00863               "{\n"
00864               "  if (index > %s) {\n"
00865               "    throw Exception(\"Index value %%u out of bounds (0..%s)\", index);\n"
00866               "  }\n"
00867               "  return data->%s[index];\n"
00868               "}\n\n",
00869               (*i).getName().c_str(),
00870               (*i).getComment().c_str(),
00871               (*i).getName().c_str(),
00872               (*i).isEnumType() ? (interface_classname + "::").c_str() : "",
00873               (*i).getPlainAccessType().c_str(),
00874               inclusion_prefix.c_str(), classname.c_str(),
00875               ( ((*i).getType() == "bool" ) ? "is_" : ""), (*i).getName().c_str(),
00876               i->getLength().c_str(), i->getLength().c_str(),
00877               (*i).getName().c_str() );
00878     }
00879 
00880     fprintf(f,
00881             "/** Get maximum length of %s value.\n"
00882             " * @return length of %s value, can be length of the array or number of \n"
00883             " * maximum number of characters for a string\n"
00884             " */\n"
00885             "size_t\n"
00886             "%s%s::maxlenof_%s() const\n"
00887             "{\n"
00888             "  return %s;\n"
00889             "}\n\n",
00890             i->getName().c_str(), i->getName().c_str(), inclusion_prefix.c_str(),
00891             classname.c_str(), i->getName().c_str(),
00892             i->getLengthValue() > 0 ? i->getLength().c_str() : "1" );
00893 
00894     fprintf(f,
00895             "/** Set %s value.\n"
00896             " * %s\n"
00897             " * @param new_%s new %s value\n"
00898             " */\n"
00899             "void\n"
00900             "%s%s::set_%s(const %s new_%s)\n"
00901             "{\n",
00902             (*i).getName().c_str(),
00903             (*i).getComment().c_str(),      
00904             (*i).getName().c_str(), (*i).getName().c_str(),
00905             inclusion_prefix.c_str(), classname.c_str(), (*i).getName().c_str(), (*i).getAccessType().c_str(), (*i).getName().c_str()
00906             );
00907     if ( (*i).getType() == "string" ) {
00908       fprintf(f,
00909               "  strncpy(data->%s, new_%s, sizeof(data->%s));\n",
00910               (*i).getName().c_str(), (*i).getName().c_str(), (*i).getName().c_str());
00911     } else if ( (*i).getLength() != "" ) {
00912       fprintf(f,
00913               "  memcpy(data->%s, new_%s, sizeof(%s) * %s);\n",
00914               (*i).getName().c_str(), (*i).getName().c_str(),
00915               (*i).getPlainAccessType().c_str(), (*i).getLength().c_str());
00916     } else {
00917       fprintf(f,
00918               "  data->%s = new_%s;\n",
00919               (*i).getName().c_str(), (*i).getName().c_str());
00920     }
00921     fprintf(f, "%s}\n\n", write_data_changed ? "  data_changed = true;\n" : "");
00922 
00923     if ( ((*i).getType() != "string") && ((*i).getLengthValue() > 0) ) {
00924       fprintf(f,
00925               "/** Set %s value at given index.\n"
00926               " * %s\n"
00927               " * @param new_%s new %s value\n"
00928               " * @param index index for of the value\n"
00929               " */\n"
00930               "void\n"
00931               "%s%s::set_%s(unsigned int index, const %s new_%s)\n"
00932               "{\n"
00933               "  if (index > %s) {\n"
00934               "    throw Exception(\"Index value %%u out of bounds (0..%s)\", index);\n"
00935               "  }\n"
00936               "  data->%s[index] = new_%s;\n"
00937               "}\n",
00938               (*i).getName().c_str(),
00939               (*i).getComment().c_str(),            
00940               (*i).getName().c_str(), (*i).getName().c_str(),
00941               inclusion_prefix.c_str(), classname.c_str(), (*i).getName().c_str(),
00942               (*i).getPlainAccessType().c_str(), i->getName().c_str(),
00943               i->getLength().c_str(), i->getLength().c_str(),
00944               i->getName().c_str(), i->getName().c_str());
00945     }
00946   }
00947 }
00948 
00949 
00950 /** Write methods to cpp file including pseudo maps.
00951  * @param f file to write to
00952  * @param interface_classname name of the interface class
00953  * @param classname name of class (can be interface or message)
00954  * @param fields fields
00955  * @param pseudo_maps pseudo maps
00956  * @param inclusion_prefix used if class is included in another class.
00957  */
00958 void
00959 CppInterfaceGenerator::write_methods_cpp(FILE *f, std::string interface_classname,
00960                                          std::string classname,
00961                                          std::vector<InterfaceField> fields,
00962                                          std::vector<InterfacePseudoMap> pseudo_maps,
00963                                          std::string inclusion_prefix)
00964 {
00965   write_methods_cpp(f, interface_classname, classname, fields,
00966                     inclusion_prefix, true);
00967 
00968   for (vector<InterfacePseudoMap>::iterator i = pseudo_maps.begin(); i != pseudo_maps.end(); ++i) {
00969     fprintf(f,
00970             "/** Get %s value.\n"
00971             " * %s\n"
00972             " * @param key key of the value\n"
00973             " * @return %s value\n"
00974             " */\n"
00975             "%s\n"
00976             "%s%s::%s(const %s key) const\n"
00977             "{\n",
00978             (*i).getName().c_str(),
00979             (*i).getComment().c_str(),
00980             (*i).getName().c_str(),
00981             (*i).getType().c_str(),
00982             inclusion_prefix.c_str(), classname.c_str(), (*i).getName().c_str(),
00983             (*i).getKeyType().c_str() );
00984 
00985     InterfacePseudoMap::RefList &reflist = i->getRefList();
00986     InterfacePseudoMap::RefList::iterator paref;
00987     bool first = true;
00988     for (paref = reflist.begin(); paref != reflist.end(); ++paref) {
00989       fprintf(f, "  %sif (key == %s) {\n"
00990                  "    return data->%s;\n",
00991                  first ? "" : "} else ",
00992               paref->second.c_str(), paref->first.c_str());
00993       first = false;
00994     }
00995     fprintf(f, "  } else {\n"
00996                "    throw Exception(\"Invalid key, cannot retrieve value\");\n"
00997                "  }\n"
00998                "}\n\n");
00999 
01000     fprintf(f,
01001             "/** Set %s value.\n"
01002             " * %s\n"
01003             " * @param key key of the value\n"
01004             " * @param new_value new value\n"
01005             " */\n"
01006             "void\n"
01007             "%s%s::set_%s(const %s key, const %s new_value)\n"
01008             "{\n",
01009             (*i).getName().c_str(),
01010             (*i).getComment().c_str(),      
01011             inclusion_prefix.c_str(), classname.c_str(), (*i).getName().c_str(),
01012             (*i).getKeyType().c_str(), (*i).getType().c_str());
01013 
01014     first = true;
01015     for (paref = reflist.begin(); paref != reflist.end(); ++paref) {
01016       fprintf(f, "  %sif (key == %s) {\n"
01017                  "    data->%s = new_value;\n",
01018                  first ? "" : "} else ",
01019               paref->second.c_str(), paref->first.c_str());
01020       first = false;
01021     }
01022 
01023     fprintf(f, "  }\n"
01024                "}\n\n");
01025   }
01026 }
01027 
01028 
01029 
01030 /** Write methods to h file.
01031  * @param f file to write to
01032  * @param is indentation space.
01033  * @param fields fields to write accessor methods for.
01034  */
01035 void
01036 CppInterfaceGenerator::write_methods_h(FILE *f, std::string /* indent space */ is,
01037                                        std::vector<InterfaceField> fields)
01038 {
01039   fprintf(f, "%s/* Methods */\n", is.c_str());
01040   for (vector<InterfaceField>::iterator i = fields.begin(); i != fields.end(); ++i) {
01041     fprintf(f,
01042             "%s%s %s%s() const;\n",
01043             is.c_str(), (*i).getAccessType().c_str(),
01044             ( ((*i).getType() == "bool" ) ? "is_" : ""),
01045             (*i).getName().c_str());
01046 
01047     if ((i->getLengthValue() > 0) && (i->getType() != "string")) {
01048       fprintf(f,
01049               "%s%s %s%s(unsigned int index) const;\n"
01050               "%svoid set_%s(unsigned int index, const %s new_%s);\n",
01051               is.c_str(), i->getPlainAccessType().c_str(),
01052               ( ((*i).getType() == "bool" ) ? "is_" : ""),
01053               (*i).getName().c_str(),
01054               is.c_str(), (*i).getName().c_str(),
01055               i->getPlainAccessType().c_str(), i->getName().c_str());
01056     }
01057 
01058     fprintf(f,
01059             "%svoid set_%s(const %s new_%s);\n"
01060             "%ssize_t maxlenof_%s() const;\n",
01061             is.c_str(), (*i).getName().c_str(),
01062             i->getAccessType().c_str(), i->getName().c_str(),
01063             is.c_str(), i->getName().c_str()
01064             );
01065   }
01066 }
01067 
01068 
01069 /** Write methods to h file.
01070  * @param f file to write to
01071  * @param is indentation space.
01072  * @param fields fields to write accessor methods for.
01073  * @param pseudo_maps pseudo maps
01074  */
01075 void
01076 CppInterfaceGenerator::write_methods_h(FILE *f, std::string /* indent space */ is,
01077                                        std::vector<InterfaceField> fields,
01078                                        std::vector<InterfacePseudoMap> pseudo_maps)
01079 {
01080   write_methods_h(f, is, fields);
01081 
01082   for (vector<InterfacePseudoMap>::iterator i = pseudo_maps.begin(); i != pseudo_maps.end(); ++i) {
01083     fprintf(f,
01084             "%s%s %s(%s key) const;\n"
01085             "%svoid set_%s(const %s key, const %s new_value);\n",
01086             is.c_str(), (*i).getType().c_str(),
01087             (*i).getName().c_str(), (*i).getKeyType().c_str(),
01088             is.c_str(), (*i).getName().c_str(),
01089             i->getKeyType().c_str(), i->getType().c_str());
01090   }
01091 }
01092 
01093 
01094 /** Write base methods header entries.
01095  * @param f file to write to
01096  * @param is indentation string
01097  */
01098 void
01099 CppInterfaceGenerator::write_basemethods_h(FILE *f, std::string is)
01100 {
01101   fprintf(f,
01102           "%svirtual Message * create_message(const char *type) const;\n\n"
01103           "%svirtual void copy_values(const Interface *other);\n"
01104           "%svirtual const char * enum_tostring(const char *enumtype, int val) const;\n",
01105           is.c_str(), is.c_str(), is.c_str());
01106 }
01107 
01108 /** Write h file.
01109  * @param f file to write to
01110  */
01111 void
01112 CppInterfaceGenerator::write_h(FILE *f)
01113 {
01114   write_header(f, filename_h);
01115   write_deflector(f);
01116 
01117   fprintf(f,
01118           "#include <interface/interface.h>\n"
01119           "#include <interface/message.h>\n"
01120           "#include <interface/field_iterator.h>\n\n"
01121           "namespace fawkes {\n\n"
01122           "class %s : public Interface\n"
01123           "{\n"
01124           " /// @cond INTERNALS\n"
01125           " INTERFACE_MGMT_FRIENDS(%s)\n"
01126           " /// @endcond\n"
01127           " public:\n",
01128           class_name.c_str(),
01129           class_name.c_str());
01130 
01131   write_constants_h(f);
01132 
01133   fprintf(f, " private:\n");
01134 
01135   write_struct(f, class_name + "_data_t", "  ", data_fields);
01136 
01137   fprintf(f, "  %s_data_t *data;\n"
01138           "\n public:\n", class_name.c_str());
01139 
01140   write_messages_h(f);
01141   fprintf(f, " private:\n");
01142   write_ctor_dtor_h(f, "  ", class_name);
01143   fprintf(f, " public:\n");
01144   write_methods_h(f, "  ", data_fields, pseudo_maps);
01145   write_basemethods_h(f, "  ");
01146   fprintf(f, "\n};\n\n} // end namespace fawkes\n\n#endif\n");
01147 }
01148 
01149 
01150 /** Generator cpp and h files.
01151  */
01152 void
01153 CppInterfaceGenerator::generate()
01154 {
01155   char timestring[26]; // 26 is mentioned in man asctime_r
01156   struct tm timestruct;
01157   time_t t = time(NULL);
01158   localtime_r(&t, &timestruct);
01159   asctime_r(&timestruct, timestring);
01160   gendate = timestring;
01161 
01162   FILE *cpp;
01163   FILE *h;
01164 
01165   cpp = fopen(string(dir + filename_cpp).c_str(), "w");
01166   h   = fopen(string(dir + filename_h).c_str(), "w");
01167 
01168   if ( cpp == NULL ) {
01169     printf("Cannot open cpp file %s%s\n", dir.c_str(), filename_cpp.c_str());
01170   }
01171   if ( h == NULL ) {
01172     printf("Cannot open h file %s%s\n", dir.c_str(), filename_h.c_str());
01173   }
01174   
01175   write_cpp(cpp);
01176   write_h(h);
01177 
01178   fclose(cpp);
01179   fclose(h);
01180 }

Generated on Tue Feb 22 13:32:24 2011 for Fawkes API by  doxygen 1.4.7