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