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