Fawkes API Fawkes Development Version
|
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, ×truct); 01159 asctime_r(×truct, 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 }