Fawkes API  Fawkes Development Version
cpp_generator.cpp
1 
2 /***************************************************************************
3  * cpp_generator.cpp - C++ Interface generator
4  *
5  * Created: Thu Oct 12 02:01:27 2006
6  * Copyright 2006-2008 Tim Niemueller [www.niemueller.de]
7  *
8  ****************************************************************************/
9 
10 /* This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU Library General Public License for more details.
19  *
20  * Read the full text in the LICENSE.GPL file in the doc directory.
21  */
22 
23 #include "cpp_generator.h"
24 #include "exceptions.h"
25 
26 #include <utils/misc/string_conversions.h>
27 
28 #include <algorithm>
29 #include <iostream>
30 #include <vector>
31 #include <time.h>
32 #include <fstream>
33 
34 using namespace std;
35 
36 
37 /** @class CppInterfaceGenerator <interfaces/generator/cpp_generator.h>
38  * Generator that transforms input from the InterfaceParser into valid
39  * C++ classes.
40  */
41 
42 /** Constructor.
43  * @param directory Directory where to create the files
44  * @param interface_name name of the interface, should end with Interface
45  * @param config_basename basename of the config without suffix
46  * @param author author of interface
47  * @param year year of copyright
48  * @param creation_date user-supplied creation date of interface
49  * @param data_comment comment in data block.
50  * @param hash MD5 hash of the config file that was used to generate the interface
51  * @param hash_size size in bytes of hash
52  * @param constants constants
53  * @param enum_constants constants defined as an enum
54  * @param data_fields data fields of the interface
55  * @param pseudo_maps pseudo maps of the interface
56  * @param messages messages defined in the interface
57  */
58 CppInterfaceGenerator::CppInterfaceGenerator(std::string directory, std::string interface_name,
59  std::string config_basename, std::string author,
60  std::string year, std::string creation_date,
61  std::string data_comment,
62  const unsigned char *hash, size_t hash_size,
63  const std::vector<InterfaceConstant> &constants,
64  const std::vector<InterfaceEnumConstant> &enum_constants,
65  const std::vector<InterfaceField> &data_fields,
66  const std::vector<InterfacePseudoMap> &pseudo_maps,
67  const std::vector<InterfaceMessage> &messages
68  )
69 {
70  this->dir = directory;
71  if ( dir.find_last_of("/") != (dir.length() - 1) ) {
72  dir += "/";
73  }
74  this->author = author;
75  this->year = year;
76  this->creation_date = creation_date;
77  this->data_comment = data_comment;
78  this->hash = hash;
79  this->hash_size = hash_size;
80  this->constants = constants;
81  this->enum_constants = enum_constants;
82  this->data_fields = data_fields;
83  this->pseudo_maps = pseudo_maps;
84  this->messages = messages;
85 
86  filename_cpp = config_basename + ".cpp";
87  filename_h = config_basename + ".h";
88  filename_o = config_basename + ".o";
89 
90  if ( interface_name.find("Interface", 0) == string::npos ) {
91  // append Interface
92  class_name = interface_name + "Interface";
93  } else {
94  class_name = interface_name;
95  }
96 
97  deflector = "__INTERFACES_" + fawkes::StringConversions::to_upper(config_basename) + "_H_";
98 }
99 
100 
101 /** Destructor */
103 {
104 }
105 
106 
107 
108 /** Write optimized struct.
109  * Create struct, try align data well, sort fields:
110  * 1. unsigned int
111  * 2. int
112  * 3. unsigned long int
113  * 4. long int
114  * 5. float
115  * 6. double
116  * 7. bool
117  * 8. byte
118  * 8. string
119  * @param f file to write to
120  * @param name name of struct
121  * @param is indentation space
122  * @param fields fields for struct
123  */
124 void
125 CppInterfaceGenerator::write_struct(FILE *f, std::string name, std::string /* indent space */ is,
126  std::vector<InterfaceField> fields)
127 {
128 
129  //stable_sort(fields.begin(), fields.end());
130 
131  fprintf(f,
132  "%s/** Internal data storage, do NOT modify! */\n"
133  "%stypedef struct __attribute__((packed)) {\n"
134  "%s int64_t timestamp_sec; /**< Interface Unix timestamp, seconds */\n"
135  "%s int64_t timestamp_usec; /**< Interface Unix timestamp, micro-seconds */\n", is.c_str(), is.c_str(), is.c_str(), is.c_str());
136 
137  for (vector<InterfaceField>::iterator i = fields.begin(); i != fields.end(); ++i) {
138  fprintf(f, "%s %s %s", is.c_str(), (*i).getStructType().c_str(), (*i).getName().c_str());
139  if ( (*i).getLength().length() > 0 ) {
140  fprintf(f, "[%s]", (*i).getLength().c_str());
141  }
142  fprintf(f, "; /**< %s */\n", (*i).getComment().c_str());
143  }
144 
145  fprintf(f, "%s} %s;\n\n", is.c_str(), name.c_str());
146 }
147 
148 
149 /** Write enum maps to header.
150  * @param f file to write to
151  */
152 void
154 {
155  for (vector<InterfaceEnumConstant>::iterator i = enum_constants.begin(); i != enum_constants.end(); ++i) {
156  fprintf(f, " interface_enum_map_t enum_map_%s;\n", i->get_name().c_str());
157  }
158 }
159 
160 
161 
162 /** Write header to file.
163  * @param f file to write to
164  * @param filename name of file
165  */
166 void
167 CppInterfaceGenerator::write_header(FILE *f, std::string filename)
168 {
169  fprintf(f,
170  "\n/***************************************************************************\n"
171  " * %s - Fawkes BlackBoard Interface - %s\n"
172  " *\n"
173  "%s%s%s"
174  " * Templated created: Thu Oct 12 10:49:19 2006\n"
175  " * Copyright %s %s\n"
176  " *\n"
177  " ****************************************************************************/\n\n"
178  "/* This program is free software; you can redistribute it and/or modify\n"
179  " * it under the terms of the GNU General Public License as published by\n"
180  " * the Free Software Foundation; either version 2 of the License, or\n"
181  " * (at your option) any later version. A runtime exception applies to\n"
182  " * this software (see LICENSE.GPL_WRE file mentioned below for details).\n"
183  " *\n"
184  " * This program is distributed in the hope that it will be useful,\n"
185  " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
186  " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
187  " * GNU Library General Public License for more details.\n"
188  " *\n"
189  " * Read the full text in the LICENSE.GPL_WRE file in the doc directory.\n"
190  " */\n\n",
191  filename.c_str(), class_name.c_str(),
192  (creation_date.length() > 0 ) ? " * Interface created: " : "",
193  (creation_date.length() > 0 ) ? creation_date.c_str() : "",
194  (creation_date.length() > 0 ) ? "\n" : "",
195  year.c_str(), (author.length() > 0) ? author.c_str() : "AllemaniACs RoboCup Team"
196  );
197 }
198 
199 
200 /** Write header deflector.
201  * @param f file to write to
202  */
203 void
205 {
206  fprintf(f, "#ifndef %s\n", deflector.c_str());
207  fprintf(f, "#define %s\n\n", deflector.c_str());
208 }
209 
210 
211 /** Write cpp file.
212  * @param f file to write to
213  */
214 void
216 {
217  write_header(f, filename_cpp);
218  fprintf(f,
219  "#include <interfaces/%s>\n\n"
220  "#include <core/exceptions/software.h>\n\n"
221  "#include <map>\n"
222  "#include <string>\n"
223  "#include <cstring>\n"
224  "#include <cstdlib>\n\n"
225  "namespace fawkes {\n\n"
226  "/** @class %s <interfaces/%s>\n"
227  " * %s Fawkes BlackBoard Interface.\n"
228  " * %s\n"
229  " * @ingroup FawkesInterfaces\n"
230  " */\n\n\n",
231  filename_h.c_str(), class_name.c_str(), filename_h.c_str(),
232  class_name.c_str(), data_comment.c_str());
233  write_constants_cpp(f);
234  write_ctor_dtor_cpp(f, class_name, "Interface", "", data_fields, messages);
235  write_enum_constants_tostring_cpp(f);
236  write_methods_cpp(f, class_name, class_name, data_fields, pseudo_maps, "");
237  write_basemethods_cpp(f);
238  write_messages_cpp(f);
239 
240  write_management_funcs_cpp(f);
241 
242  fprintf(f, "\n} // end namespace fawkes\n");
243 }
244 
245 
246 /** Write management functions.
247  * @param f file to write to
248  */
249 void
251 {
252  fprintf(f,
253  "/// @cond INTERNALS\n"
254  "EXPORT_INTERFACE(%s)\n"
255  "/// @endcond\n\n",
256  class_name.c_str());
257 }
258 
259 
260 /** Write constants to cpp file.
261  * @param f file to write to
262  */
263 void
265 {
266  for ( vector<InterfaceConstant>::iterator i = constants.begin(); i != constants.end(); ++i) {
267  const char *type_suffix = "";
268  if (i->getType() == "uint32_t") {
269  type_suffix = "u";
270  }
271  fprintf(f,
272  "/** %s constant */\n"
273  "const %s %s::%s = %s%s;\n",
274  (*i).getName().c_str(),
275  (*i).getType().c_str(),
276  class_name.c_str(), i->getName().c_str(),
277  i->getValue().c_str(), type_suffix);
278  }
279  fprintf(f, "\n");
280 }
281 
282 
283 /** Write enum constant tostring methods to cpp file.
284  * @param f file to write to
285  */
286 void
288 {
289  for ( vector<InterfaceEnumConstant>::iterator i = enum_constants.begin(); i != enum_constants.end(); ++i) {
290  fprintf(f,
291  "/** Convert %s constant to string.\n"
292  " * @param value value to convert to string\n"
293  " * @return constant value as string.\n"
294  " */\n"
295  "const char *\n"
296  "%s::tostring_%s(%s value) const\n"
297  "{\n"
298  " switch (value) {\n",
299  i->get_name().c_str(), class_name.c_str(), i->get_name().c_str(),
300  i->get_name().c_str());
301  vector<InterfaceEnumConstant::EnumItem> items = i->get_items();
302  vector<InterfaceEnumConstant::EnumItem>::iterator j;
303  for (j = items.begin(); j != items.end(); ++j) {
304  fprintf(f, " case %s: return \"%s\";\n",
305  j->name.c_str(), j->name.c_str());
306  }
307  fprintf(f,
308  " default: return \"UNKNOWN\";\n"
309  " }\n"
310  "}\n");
311  }
312 }
313 
314 /** Write constants to h file
315  * @param f file to write to
316  */
317 void
319 {
320  fprintf(f, " /* constants */\n");
321  for ( vector<InterfaceConstant>::iterator i = constants.begin(); i != constants.end(); ++i) {
322  fprintf(f, " static const %s %s;\n", (*i).getType().c_str(), (*i).getName().c_str());
323  }
324  fprintf(f, "\n");
325 
326  for ( vector<InterfaceEnumConstant>::iterator i = enum_constants.begin(); i != enum_constants.end(); ++i) {
327  fprintf(f,
328  " /** %s */\n"
329  " typedef enum {\n",
330  (*i).get_comment().c_str());
331  vector<InterfaceEnumConstant::EnumItem> items = i->get_items();
332  vector<InterfaceEnumConstant::EnumItem>::iterator j = items.begin();
333  while (j != items.end()) {
334  if (j->has_custom_value) {
335  fprintf(f, " %s = %i /**< %s */", j->name.c_str(),
336  j->custom_value, j->comment.c_str());
337  } else {
338  fprintf(f, " %s /**< %s */", j->name.c_str(), j->comment.c_str());
339  }
340  ++j;
341  if ( j != items.end() ) {
342  fprintf(f, ",\n");
343  } else {
344  fprintf(f, "\n");
345  }
346  }
347  fprintf(f, " } %s;\n", (*i).get_name().c_str());
348  fprintf(f, " const char * tostring_%s(%s value) const;\n\n",
349  i->get_name().c_str(), i->get_name().c_str());
350  }
351 }
352 
353 
354 /** Write messages to h file.
355  * @param f file to write to
356  */
357 void
359 {
360  fprintf(f, " /* messages */\n");
361  for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
362  fprintf(f, " class %s : public Message\n"
363  " {\n", (*i).getName().c_str());
364 
365  fprintf(f, " private:\n");
366  write_struct(f, (*i).getName() + "_data_t", " ", (*i).getFields());
367  fprintf(f,
368  " %s_data_t *data;\n\n",
369  (*i).getName().c_str());
370 
371  write_enum_maps_h(f);
372 
373  fprintf(f, " public:\n");
374  write_message_ctor_dtor_h(f, " ", (*i).getName(), (*i).getFields());
375  write_methods_h(f, " ", (*i).getFields());
376  write_message_clone_method_h(f, " ");
377  fprintf(f, " };\n\n");
378  }
379  fprintf(f, " virtual bool message_valid(const Message *message) const;\n");
380 
381 }
382 
383 
384 /** Write messages to cpp file.
385  * @param f file to write to
386  */
387 void
389 {
390  fprintf(f, "/* =========== messages =========== */\n");
391  for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
392  fprintf(f,
393  "/** @class %s::%s <interfaces/%s>\n"
394  " * %s Fawkes BlackBoard Interface Message.\n"
395  " * %s\n"
396  " */\n\n\n",
397  class_name.c_str(), (*i).getName().c_str(), filename_h.c_str(),
398  (*i).getName().c_str(), (*i).getComment().c_str());
399 
400  write_message_ctor_dtor_cpp(f, (*i).getName(), "Message", class_name + "::",
401  (*i).getFields());
402  write_methods_cpp(f, class_name, (*i).getName(), (*i).getFields(), class_name + "::", false);
403  write_message_clone_method_cpp(f, (class_name + "::" + (*i).getName()).c_str());
404  }
405  fprintf(f,
406  "/** Check if message is valid and can be enqueued.\n"
407  " * @param message Message to check\n"
408  " * @return true if the message is valid, false otherwise.\n"
409  " */\n"
410  "bool\n"
411  "%s::message_valid(const Message *message) const\n"
412  "{\n", class_name.c_str());
413  unsigned int n = 0;
414  for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
415  fprintf(f,
416  " const %s *m%u = dynamic_cast<const %s *>(message);\n"
417  " if ( m%u != NULL ) {\n"
418  " return true;\n"
419  " }\n",
420  (*i).getName().c_str(), n, (*i).getName().c_str(), n);
421  ++n;
422  }
423  fprintf(f,
424  " return false;\n"
425  "}\n\n");
426 }
427 
428 
429 /** Write create_message() method to cpp file.
430  * @param f file to write to
431  */
432 void
434 {
435  fprintf(f, "/* =========== message create =========== */\n");
436  fprintf(f,
437  "Message *\n"
438  "%s::create_message(const char *type) const\n"
439  "{\n", class_name.c_str());
440 
441  bool first = true;
442  for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
443  fprintf(f,
444  " %sif ( strncmp(\"%s\", type, __INTERFACE_MESSAGE_TYPE_SIZE) == 0 ) {\n"
445  " return new %s();\n",
446  first ? "" : "} else ", i->getName().c_str(), i->getName().c_str());
447  first = false;
448  }
449  if (first) {
450  fprintf(f,
451  " throw UnknownTypeException(\"The given type '%%s' does not match any known \"\n"
452  " \"message type for this interface type.\", type);\n"
453  "}\n\n\n");
454  } else {
455  fprintf(f,
456  " } else {\n"
457  " throw UnknownTypeException(\"The given type '%%s' does not match any known \"\n"
458  " \"message type for this interface type.\", type);\n"
459  " }\n"
460  "}\n\n\n");
461  }
462 }
463 
464 
465 /** Write copy_value() method to CPP file.
466  * @param f file to write to
467  */
468 void
470 {
471  fprintf(f,
472  "/** Copy values from other interface.\n"
473  " * @param other other interface to copy values from\n"
474  " */\n"
475  "void\n"
476  "%s::copy_values(const Interface *other)\n"
477  "{\n"
478  " const %s *oi = dynamic_cast<const %s *>(other);\n"
479  " if (oi == NULL) {\n"
480  " throw TypeMismatchException(\"Can only copy values from interface of same type (%%s vs. %%s)\",\n"
481  " type(), other->type());\n"
482  " }\n"
483  " memcpy(data, oi->data, sizeof(%s_data_t));\n"
484  "}\n\n",
485  class_name.c_str(), class_name.c_str(), class_name.c_str(), class_name.c_str());
486 }
487 
488 
489 /** Write enum_tostring() method to CPP file.
490  * @param f file to write to
491  */
492 void
494 {
495  fprintf(f,
496  "const char *\n"
497  "%s::enum_tostring(const char *enumtype, int val) const\n"
498  "{\n", class_name.c_str());
499  for ( vector<InterfaceEnumConstant>::iterator i = enum_constants.begin(); i != enum_constants.end(); ++i) {
500  fprintf(f,
501  " if (strcmp(enumtype, \"%s\") == 0) {\n"
502  " return tostring_%s((%s)val);\n"
503  " }\n",
504  i->get_name().c_str(), i->get_name().c_str(), i->get_name().c_str());
505  }
506  fprintf(f,
507  " throw UnknownTypeException(\"Unknown enum type %%s\", enumtype);\n"
508  "}\n\n");
509 }
510 
511 
512 /** Write base methods.
513  * @param f file to write to
514  */
515 void
517 {
518  write_create_message_method_cpp(f);
519  write_copy_value_method_cpp(f);
520  write_enum_tostring_method_cpp(f);
521 }
522 
523 
524 /** Write constructor and destructor to h file.
525  * @param f file to write to
526  * @param is indentation space
527  * @param classname name of class
528  */
529 void
530 CppInterfaceGenerator::write_ctor_dtor_h(FILE *f, std::string /* indent space */ is,
531  std::string classname)
532 {
533  fprintf(f,
534  "%s%s();\n"
535  "%s~%s();\n\n",
536  is.c_str(), classname.c_str(),
537  is.c_str(), classname.c_str());
538 }
539 
540 
541 /** Write constructor and destructor for message to h file.
542  * @param f file to write to
543  * @param is indentation space
544  * @param classname name of class
545  * @param fields vector of data fields of message
546  */
547 void
548 CppInterfaceGenerator::write_message_ctor_dtor_h(FILE *f, std::string /* indent space */ is,
549  std::string classname,
550  std::vector<InterfaceField> fields)
551 {
552  vector<InterfaceField>::iterator i;
553 
554  if ( fields.size() > 0 ) {
555 
556  fprintf(f, "%s%s(", is.c_str(), classname.c_str());
557 
558  i = fields.begin();
559  while (i != fields.end()) {
560  fprintf(f, "const %s ini_%s",
561  (*i).getAccessType().c_str(), (*i).getName().c_str());
562  ++i;
563  if ( i != fields.end() ) {
564  fprintf(f, ", ");
565  }
566  }
567 
568  fprintf(f, ");\n");
569  }
570 
571  write_ctor_dtor_h(f, is, classname);
572  fprintf(f, "%s%s(const %s *m);\n", is.c_str(), classname.c_str(), classname.c_str());
573 
574 }
575 
576 
577 /** Write message clone method header.
578  * @param f file to write to
579  * @param is indentation space
580  */
581 void
583 {
584  fprintf(f, "%svirtual Message * clone() const;\n", is.c_str());
585 }
586 
587 
588 /** Write message clone method.
589  * @param f file to write to
590  * @param classname name of message class
591  */
592 void
594 {
595  fprintf(f,
596  "/** Clone this message.\n"
597  " * Produces a message of the same type as this message and copies the\n"
598  " * data to the new message.\n"
599  " * @return clone of this message\n"
600  " */\n"
601  "Message *\n"
602  "%s::clone() const\n"
603  "{\n"
604  " return new %s(this);\n"
605  "}\n", classname.c_str(), classname.c_str());
606 }
607 
608 /** Write enum maps.
609  * @param f file to write to
610  */
611 void
613 {
614  for (vector<InterfaceEnumConstant>::iterator i = enum_constants.begin(); i != enum_constants.end(); ++i) {
615  const std::vector<InterfaceEnumConstant::EnumItem> &enum_values = i->get_items();
616 
617  std::vector<InterfaceEnumConstant::EnumItem>::const_iterator ef;
618  for (ef = enum_values.begin(); ef != enum_values.end(); ++ef) {
619  fprintf(f,
620  " enum_map_%s[(int)%s] = \"%s\";\n",
621  i->get_name().c_str(), ef->name.c_str(), ef->name.c_str());
622  }
623  }
624 }
625 
626 
627 /** Write the add_fieldinfo() calls.
628  * @param f file to write to
629  * @param fields fields to write field info for
630  */
631 void
632 CppInterfaceGenerator::write_add_fieldinfo_calls(FILE *f, std::vector<InterfaceField> &fields)
633 {
634  std::vector<InterfaceField>::iterator i;
635  for (i = fields.begin(); i != fields.end(); ++i) {
636  const char *type = "";
637  const char *dataptr = "&";
638  std::string enumtype;
639 
640  if ( i->getType() == "bool" ) {
641  type = "BOOL";
642  } else if ( i->getType() == "int8" ) {
643  type = "INT8";
644  } else if ( i->getType() == "uint8" ) {
645  type = "UINT8";
646  } else if ( i->getType() == "int16" ) {
647  type = "INT16";
648  } else if ( i->getType() == "uint16" ) {
649  type = "UINT16";
650  } else if ( i->getType() == "int32" ) {
651  type = "INT32";
652  } else if ( i->getType() == "uint32" ) {
653  type = "UINT32";
654  } else if ( i->getType() == "int64" ) {
655  type = "INT64";
656  } else if ( i->getType() == "uint64" ) {
657  type = "UINT64";
658  } else if ( i->getType() == "byte" ) {
659  type = "BYTE";
660  } else if ( i->getType() == "float" ) {
661  type = "FLOAT";
662  } else if ( i->getType() == "double" ) {
663  type = "DOUBLE";
664  } else if ( i->getType() == "string" ) {
665  type = "STRING";
666  dataptr = "";
667  } else {
668  type = "ENUM";
669  enumtype = i->getType();
670  }
671 
672  fprintf(f, " add_fieldinfo(IFT_%s, \"%s\", %u, %sdata->%s%s%s%s%s%s%s);\n",
673  type, i->getName().c_str(),
674  (i->getLengthValue() > 0) ? i->getLengthValue() : 1,
675  dataptr, i->getName().c_str(),
676  enumtype.empty() ? "" : ", \"",
677  enumtype.empty() ? "" : enumtype.c_str(),
678  enumtype.empty() ? "" : "\"",
679  enumtype.empty() ? "" : ", ",
680  enumtype.empty() ? "" : "&enum_map_",
681  enumtype.empty() ? "" : enumtype.c_str()
682  );
683  }
684 }
685 
686 
687 /** Write constructor and destructor to cpp file.
688  * @param f file to write to
689  * @param classname name of class
690  * @param super_class name of base class
691  * @param inclusion_prefix Used if class is included in another class.
692  * @param fields fields
693  * @param messages messages
694  */
695 void
697  std::string classname, std::string super_class,
698  std::string inclusion_prefix,
699  std::vector<InterfaceField> fields,
700  std::vector<InterfaceMessage> messages)
701 {
702  fprintf(f,
703  "/** Constructor */\n"
704  "%s%s::%s() : %s()\n"
705  "{\n",
706  inclusion_prefix.c_str(), classname.c_str(),
707  classname.c_str(), super_class.c_str());
708 
709  fprintf(f,
710  " data_size = sizeof(%s_data_t);\n"
711  " data_ptr = malloc(data_size);\n"
712  " data = (%s_data_t *)data_ptr;\n"
713  " data_ts = (interface_data_ts_t *)data_ptr;\n"
714  " memset(data_ptr, 0, data_size);\n",
715  classname.c_str(), classname.c_str());
716 
717  write_enum_map_population(f);
718  write_add_fieldinfo_calls(f, fields);
719 
720  for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
721  fprintf(f, " add_messageinfo(\"%s\");\n", i->getName().c_str());
722  }
723 
724  fprintf(f, " unsigned char tmp_hash[] = {");
725  for (size_t st = 0; st < hash_size-1; ++st) {
726  fprintf(f, "%#02x, ", hash[st]);
727  }
728  fprintf(f, "%#02x};\n", hash[hash_size-1]);
729  fprintf(f, " set_hash(tmp_hash);\n");
730 
731  fprintf(f,
732  "}\n\n"
733  "/** Destructor */\n"
734  "%s%s::~%s()\n"
735  "{\n"
736  " free(data_ptr);\n"
737  "}\n",
738  inclusion_prefix.c_str(), classname.c_str(), classname.c_str()
739  );
740 }
741 
742 
743 /** Write constructor and destructor for message to cpp file.
744  * @param f file to write to
745  * @param classname name of class
746  * @param super_class name of base class
747  * @param inclusion_prefix Used if class is included in another class.
748  * @param fields vector of data fields of message
749  */
750 void
752  std::string classname, std::string super_class,
753  std::string inclusion_prefix,
754  std::vector<InterfaceField> fields)
755 {
756  vector<InterfaceField>::iterator i;
757 
758  if ( fields.size() > 0 ) {
759  fprintf(f,
760  "/** Constructor with initial values.\n");
761 
762  for (i = fields.begin(); i != fields.end(); ++i) {
763  fprintf(f, " * @param ini_%s initial value for %s\n",
764  (*i).getName().c_str(), (*i).getName().c_str());
765  }
766 
767  fprintf(f,
768  " */\n"
769  "%s%s::%s(",
770  inclusion_prefix.c_str(), classname.c_str(), classname.c_str());
771 
772  i = fields.begin();
773  while (i != fields.end()) {
774  fprintf(f, "const %s ini_%s",
775  (*i).getAccessType().c_str(), (*i).getName().c_str());
776  ++i;
777  if ( i != fields.end() ) {
778  fprintf(f, ", ");
779  }
780  }
781 
782  fprintf(f,") : %s(\"%s\")\n"
783  "{\n"
784  " data_size = sizeof(%s_data_t);\n"
785  " data_ptr = malloc(data_size);\n"
786  " memset(data_ptr, 0, data_size);\n"
787  " data = (%s_data_t *)data_ptr;\n"
788  " data_ts = (message_data_ts_t *)data_ptr;\n",
789  super_class.c_str(), classname.c_str(), classname.c_str(), classname.c_str());
790 
791  for (i = fields.begin(); i != fields.end(); ++i) {
792  if ( (*i).getType() == "string" ) {
793  fprintf(f, " strncpy(data->%s, ini_%s, %s);\n",
794  (*i).getName().c_str(), (*i).getName().c_str(),
795  (*i).getLength().c_str());
796  } else if (i->getLengthValue() > 1) {
797  fprintf(f, " memcpy(data->%s, ini_%s, sizeof(%s) * %s);\n",
798  i->getName().c_str(), i->getName().c_str(),
799  i->getPlainAccessType().c_str(), i->getLength().c_str());
800 
801 
802  } else {
803  fprintf(f, " data->%s = ini_%s;\n",
804  (*i).getName().c_str(), (*i).getName().c_str());
805  }
806  }
807 
808  write_enum_map_population(f);
809  write_add_fieldinfo_calls(f, fields);
810 
811  fprintf(f, "}\n");
812  }
813 
814  fprintf(f,
815  "/** Constructor */\n"
816  "%s%s::%s() : %s(\"%s\")\n"
817  "{\n",
818  inclusion_prefix.c_str(), classname.c_str(),
819  classname.c_str(), super_class.c_str(), classname.c_str());
820 
821  fprintf(f,
822  " data_size = sizeof(%s_data_t);\n"
823  " data_ptr = malloc(data_size);\n"
824  " memset(data_ptr, 0, data_size);\n"
825  " data = (%s_data_t *)data_ptr;\n"
826  " data_ts = (message_data_ts_t *)data_ptr;\n",
827  classname.c_str(), classname.c_str());
828 
829  write_enum_map_population(f);
830  write_add_fieldinfo_calls(f, fields);
831 
832  fprintf(f,
833  "}\n\n"
834  "/** Destructor */\n"
835  "%s%s::~%s()\n"
836  "{\n"
837  " free(data_ptr);\n"
838  "}\n\n",
839  inclusion_prefix.c_str(), classname.c_str(), classname.c_str());
840 
841  fprintf(f,
842  "/** Copy constructor.\n"
843  " * @param m message to copy from\n"
844  " */\n"
845  "%s%s::%s(const %s *m) : %s(\"%s\")\n"
846  "{\n",
847  inclusion_prefix.c_str(), classname.c_str(), classname.c_str(),
848  classname.c_str(), super_class.c_str(), classname.c_str());
849 
850  fprintf(f,
851  " data_size = m->data_size;\n"
852  " data_ptr = malloc(data_size);\n"
853  " memcpy(data_ptr, m->data_ptr, data_size);\n"
854  " data = (%s_data_t *)data_ptr;\n"
855  " data_ts = (message_data_ts_t *)data_ptr;\n",
856  classname.c_str());
857 
858 
859  fprintf(f, "}\n\n");
860 }
861 
862 
863 /** Write methods to cpp file.
864  * @param f file to write to
865  * @param interface_classname name of the interface class
866  * @param classname name of class (can be interface or message)
867  * @param fields fields
868  * @param inclusion_prefix used if class is included in another class.
869  * @param write_data_changed if true writes code that sets the interface's
870  * data_changed flag. Set to true for interface methods, false for message
871  * methods.
872  */
873 void
874 CppInterfaceGenerator::write_methods_cpp(FILE *f, std::string interface_classname,
875  std::string classname,
876  std::vector<InterfaceField> fields,
877  std::string inclusion_prefix,
878  bool write_data_changed)
879 {
880  fprintf(f, "/* Methods */\n");
881  for (vector<InterfaceField>::iterator i = fields.begin(); i != fields.end(); ++i) {
882  fprintf(f,
883  "/** Get %s value.\n"
884  " * %s\n"
885  " * @return %s value\n"
886  " */\n"
887  "%s%s\n"
888  "%s%s::%s%s() const\n"
889  "{\n"
890  " return %sdata->%s;\n"
891  "}\n\n",
892  (*i).getName().c_str(),
893  (*i).getComment().c_str(),
894  (*i).getName().c_str(),
895  (*i).isEnumType() ? (interface_classname + "::").c_str() : "",
896  (*i).getAccessType().c_str(),
897  inclusion_prefix.c_str(), classname.c_str(), ( ((*i).getType() == "bool" ) ? "is_" : ""), (*i).getName().c_str(),
898  (*i).isEnumType() ? (std::string("(") + interface_classname + "::" +
899  i->getAccessType() + ")").c_str() : "",
900  (*i).getName().c_str() );
901 
902  if ( (i->getLengthValue() > 0) && (i->getType() != "string") ) {
903  fprintf(f,
904  "/** Get %s value at given index.\n"
905  " * %s\n"
906  " * @param index index of value\n"
907  " * @return %s value\n"
908  " * @exception Exception thrown if index is out of bounds\n"
909  " */\n"
910  "%s%s\n"
911  "%s%s::%s%s(unsigned int index) const\n"
912  "{\n"
913  " if (index > %s) {\n"
914  " throw Exception(\"Index value %%u out of bounds (0..%s)\", index);\n"
915  " }\n"
916  " return %sdata->%s[index];\n"
917  "}\n\n",
918  (*i).getName().c_str(),
919  (*i).getComment().c_str(),
920  (*i).getName().c_str(),
921  (*i).isEnumType() ? (interface_classname + "::").c_str() : "",
922  (*i).getPlainAccessType().c_str(),
923  inclusion_prefix.c_str(), classname.c_str(),
924  ( ((*i).getType() == "bool" ) ? "is_" : ""), (*i).getName().c_str(),
925  i->getLength().c_str(), i->getLength().c_str(),
926  (*i).isEnumType() ? (std::string("(") + interface_classname + "::" +
927  i->getPlainAccessType() + ")").c_str() : "",
928  (*i).getName().c_str() );
929  }
930 
931  fprintf(f,
932  "/** Get maximum length of %s value.\n"
933  " * @return length of %s value, can be length of the array or number of \n"
934  " * maximum number of characters for a string\n"
935  " */\n"
936  "size_t\n"
937  "%s%s::maxlenof_%s() const\n"
938  "{\n"
939  " return %s;\n"
940  "}\n\n",
941  i->getName().c_str(), i->getName().c_str(), inclusion_prefix.c_str(),
942  classname.c_str(), i->getName().c_str(),
943  i->getLengthValue() > 0 ? i->getLength().c_str() : "1" );
944 
945  fprintf(f,
946  "/** Set %s value.\n"
947  " * %s\n"
948  " * @param new_%s new %s value\n"
949  " */\n"
950  "void\n"
951  "%s%s::set_%s(const %s new_%s)\n"
952  "{\n",
953  (*i).getName().c_str(),
954  (*i).getComment().c_str(),
955  (*i).getName().c_str(), (*i).getName().c_str(),
956  inclusion_prefix.c_str(), classname.c_str(), (*i).getName().c_str(), (*i).getAccessType().c_str(), (*i).getName().c_str()
957  );
958  if ( (*i).getType() == "string" ) {
959  fprintf(f,
960  " strncpy(data->%s, new_%s, sizeof(data->%s));\n",
961  (*i).getName().c_str(), (*i).getName().c_str(), (*i).getName().c_str());
962  } else if ( (*i).getLength() != "" ) {
963  fprintf(f,
964  " memcpy(data->%s, new_%s, sizeof(%s) * %s);\n",
965  (*i).getName().c_str(), (*i).getName().c_str(),
966  (*i).getPlainAccessType().c_str(), (*i).getLength().c_str());
967  } else {
968  fprintf(f,
969  " data->%s = new_%s;\n",
970  (*i).getName().c_str(), (*i).getName().c_str());
971  }
972  fprintf(f, "%s}\n\n", write_data_changed ? " data_changed = true;\n" : "");
973 
974  if ( ((*i).getType() != "string") && ((*i).getLengthValue() > 0) ) {
975  fprintf(f,
976  "/** Set %s value at given index.\n"
977  " * %s\n"
978  " * @param new_%s new %s value\n"
979  " * @param index index for of the value\n"
980  " */\n"
981  "void\n"
982  "%s%s::set_%s(unsigned int index, const %s new_%s)\n"
983  "{\n"
984  " if (index > %s) {\n"
985  " throw Exception(\"Index value %%u out of bounds (0..%s)\", index);\n"
986  " }\n"
987  " data->%s[index] = new_%s;\n"
988  "%s"
989  "}\n",
990  (*i).getName().c_str(),
991  (*i).getComment().c_str(),
992  (*i).getName().c_str(), (*i).getName().c_str(),
993  inclusion_prefix.c_str(), classname.c_str(), (*i).getName().c_str(),
994  (*i).getPlainAccessType().c_str(), i->getName().c_str(),
995  i->getLength().c_str(), i->getLength().c_str(),
996  i->getName().c_str(), i->getName().c_str(),
997  write_data_changed ? " data_changed = true;\n" : "");
998  }
999  }
1000 }
1001 
1002 
1003 /** Write methods to cpp file including pseudo maps.
1004  * @param f file to write to
1005  * @param interface_classname name of the interface class
1006  * @param classname name of class (can be interface or message)
1007  * @param fields fields
1008  * @param pseudo_maps pseudo maps
1009  * @param inclusion_prefix used if class is included in another class.
1010  */
1011 void
1012 CppInterfaceGenerator::write_methods_cpp(FILE *f, std::string interface_classname,
1013  std::string classname,
1014  std::vector<InterfaceField> fields,
1015  std::vector<InterfacePseudoMap> pseudo_maps,
1016  std::string inclusion_prefix)
1017 {
1018  write_methods_cpp(f, interface_classname, classname, fields,
1019  inclusion_prefix, true);
1020 
1021  for (vector<InterfacePseudoMap>::iterator i = pseudo_maps.begin(); i != pseudo_maps.end(); ++i) {
1022  fprintf(f,
1023  "/** Get %s value.\n"
1024  " * %s\n"
1025  " * @param key key of the value\n"
1026  " * @return %s value\n"
1027  " */\n"
1028  "%s\n"
1029  "%s%s::%s(const %s key) const\n"
1030  "{\n",
1031  (*i).getName().c_str(),
1032  (*i).getComment().c_str(),
1033  (*i).getName().c_str(),
1034  (*i).getType().c_str(),
1035  inclusion_prefix.c_str(), classname.c_str(), (*i).getName().c_str(),
1036  (*i).getKeyType().c_str() );
1037 
1038  InterfacePseudoMap::RefList &reflist = i->getRefList();
1039  InterfacePseudoMap::RefList::iterator paref;
1040  bool first = true;
1041  for (paref = reflist.begin(); paref != reflist.end(); ++paref) {
1042  fprintf(f, " %sif (key == %s) {\n"
1043  " return data->%s;\n",
1044  first ? "" : "} else ",
1045  paref->second.c_str(), paref->first.c_str());
1046  first = false;
1047  }
1048  fprintf(f, " } else {\n"
1049  " throw Exception(\"Invalid key, cannot retrieve value\");\n"
1050  " }\n"
1051  "}\n\n");
1052 
1053  fprintf(f,
1054  "/** Set %s value.\n"
1055  " * %s\n"
1056  " * @param key key of the value\n"
1057  " * @param new_value new value\n"
1058  " */\n"
1059  "void\n"
1060  "%s%s::set_%s(const %s key, const %s new_value)\n"
1061  "{\n",
1062  (*i).getName().c_str(),
1063  (*i).getComment().c_str(),
1064  inclusion_prefix.c_str(), classname.c_str(), (*i).getName().c_str(),
1065  (*i).getKeyType().c_str(), (*i).getType().c_str());
1066 
1067  first = true;
1068  for (paref = reflist.begin(); paref != reflist.end(); ++paref) {
1069  fprintf(f, " %sif (key == %s) {\n"
1070  " data->%s = new_value;\n",
1071  first ? "" : "} else ",
1072  paref->second.c_str(), paref->first.c_str());
1073  first = false;
1074  }
1075 
1076  fprintf(f, " }\n"
1077  "}\n\n");
1078  }
1079 }
1080 
1081 
1082 
1083 /** Write methods to h file.
1084  * @param f file to write to
1085  * @param is indentation space.
1086  * @param fields fields to write accessor methods for.
1087  */
1088 void
1089 CppInterfaceGenerator::write_methods_h(FILE *f, std::string /* indent space */ is,
1090  std::vector<InterfaceField> fields)
1091 {
1092  fprintf(f, "%s/* Methods */\n", is.c_str());
1093  for (vector<InterfaceField>::iterator i = fields.begin(); i != fields.end(); ++i) {
1094  fprintf(f,
1095  "%s%s %s%s() const;\n",
1096  is.c_str(), (*i).getAccessType().c_str(),
1097  ( ((*i).getType() == "bool" ) ? "is_" : ""),
1098  (*i).getName().c_str());
1099 
1100  if ((i->getLengthValue() > 0) && (i->getType() != "string")) {
1101  fprintf(f,
1102  "%s%s %s%s(unsigned int index) const;\n"
1103  "%svoid set_%s(unsigned int index, const %s new_%s);\n",
1104  is.c_str(), i->getPlainAccessType().c_str(),
1105  ( ((*i).getType() == "bool" ) ? "is_" : ""),
1106  (*i).getName().c_str(),
1107  is.c_str(), (*i).getName().c_str(),
1108  i->getPlainAccessType().c_str(), i->getName().c_str());
1109  }
1110 
1111  fprintf(f,
1112  "%svoid set_%s(const %s new_%s);\n"
1113  "%ssize_t maxlenof_%s() const;\n",
1114  is.c_str(), (*i).getName().c_str(),
1115  i->getAccessType().c_str(), i->getName().c_str(),
1116  is.c_str(), i->getName().c_str()
1117  );
1118  }
1119 }
1120 
1121 
1122 /** Write methods to h file.
1123  * @param f file to write to
1124  * @param is indentation space.
1125  * @param fields fields to write accessor methods for.
1126  * @param pseudo_maps pseudo maps
1127  */
1128 void
1129 CppInterfaceGenerator::write_methods_h(FILE *f, std::string /* indent space */ is,
1130  std::vector<InterfaceField> fields,
1131  std::vector<InterfacePseudoMap> pseudo_maps)
1132 {
1133  write_methods_h(f, is, fields);
1134 
1135  for (vector<InterfacePseudoMap>::iterator i = pseudo_maps.begin(); i != pseudo_maps.end(); ++i) {
1136  fprintf(f,
1137  "%s%s %s(%s key) const;\n"
1138  "%svoid set_%s(const %s key, const %s new_value);\n",
1139  is.c_str(), (*i).getType().c_str(),
1140  (*i).getName().c_str(), (*i).getKeyType().c_str(),
1141  is.c_str(), (*i).getName().c_str(),
1142  i->getKeyType().c_str(), i->getType().c_str());
1143  }
1144 }
1145 
1146 
1147 /** Write base methods header entries.
1148  * @param f file to write to
1149  * @param is indentation string
1150  */
1151 void
1153 {
1154  fprintf(f,
1155  "%svirtual Message * create_message(const char *type) const;\n\n"
1156  "%svirtual void copy_values(const Interface *other);\n"
1157  "%svirtual const char * enum_tostring(const char *enumtype, int val) const;\n",
1158  is.c_str(), is.c_str(), is.c_str());
1159 }
1160 
1161 /** Write h file.
1162  * @param f file to write to
1163  */
1164 void
1166 {
1167  write_header(f, filename_h);
1168  write_deflector(f);
1169 
1170  fprintf(f,
1171  "#include <interface/interface.h>\n"
1172  "#include <interface/message.h>\n"
1173  "#include <interface/field_iterator.h>\n\n"
1174  "namespace fawkes {\n\n"
1175  "class %s : public Interface\n"
1176  "{\n"
1177  " /// @cond INTERNALS\n"
1178  " INTERFACE_MGMT_FRIENDS(%s)\n"
1179  " /// @endcond\n"
1180  " public:\n",
1181  class_name.c_str(),
1182  class_name.c_str());
1183 
1184  write_constants_h(f);
1185 
1186  fprintf(f, " private:\n");
1187 
1188  write_struct(f, class_name + "_data_t", " ", data_fields);
1189 
1190  fprintf(f, " %s_data_t *data;\n\n", class_name.c_str());
1191 
1192  write_enum_maps_h(f);
1193 
1194  fprintf(f, " public:\n");
1195 
1196  write_messages_h(f);
1197  fprintf(f, " private:\n");
1198  write_ctor_dtor_h(f, " ", class_name);
1199  fprintf(f, " public:\n");
1200  write_methods_h(f, " ", data_fields, pseudo_maps);
1201  write_basemethods_h(f, " ");
1202  fprintf(f, "\n};\n\n} // end namespace fawkes\n\n#endif\n");
1203 }
1204 
1205 
1206 /** Generator cpp and h files.
1207  */
1208 void
1210 {
1211  char timestring[26]; // 26 is mentioned in man asctime_r
1212  struct tm timestruct;
1213  time_t t = time(NULL);
1214  localtime_r(&t, &timestruct);
1215  asctime_r(&timestruct, timestring);
1216  gendate = timestring;
1217 
1218  FILE *cpp;
1219  FILE *h;
1220 
1221  cpp = fopen(string(dir + filename_cpp).c_str(), "w");
1222  h = fopen(string(dir + filename_h).c_str(), "w");
1223 
1224  if ( cpp == NULL ) {
1225  printf("Cannot open cpp file %s%s\n", dir.c_str(), filename_cpp.c_str());
1226  }
1227  if ( h == NULL ) {
1228  printf("Cannot open h file %s%s\n", dir.c_str(), filename_h.c_str());
1229  }
1230 
1231  write_cpp(cpp);
1232  write_h(h);
1233 
1234  fclose(cpp);
1235  fclose(h);
1236 }
CppInterfaceGenerator(std::string directory, std::string interface_name, std::string config_basename, std::string author, std::string year, std::string creation_date, std::string data_comment, const unsigned char *hash, size_t hash_size, const std::vector< InterfaceConstant > &constants, const std::vector< InterfaceEnumConstant > &enum_constants, const std::vector< InterfaceField > &data_fields, const std::vector< InterfacePseudoMap > &pseudo_maps, const std::vector< InterfaceMessage > &messages)
Constructor.
void write_add_fieldinfo_calls(FILE *f, std::vector< InterfaceField > &fields)
Write the add_fieldinfo() calls.
void write_message_ctor_dtor_cpp(FILE *f, std::string classname, std::string super_class, std::string inclusion_prefix, std::vector< InterfaceField > fields)
Write constructor and destructor for message to cpp file.
static std::string to_upper(std::string str)
Convert string to all-uppercase string.
void write_enum_map_population(FILE *f)
Write enum maps.
void write_messages_cpp(FILE *f)
Write messages to cpp file.
void write_management_funcs_cpp(FILE *f)
Write management functions.
void write_deflector(FILE *f)
Write header deflector.
void write_struct(FILE *f, std::string name, std::string is, std::vector< InterfaceField > fields)
Write optimized struct.
void write_basemethods_h(FILE *f, std::string is)
Write base methods header entries.
STL namespace.
void write_constants_h(FILE *f)
Write constants to h file.
void generate()
Generator cpp and h files.
void write_cpp(FILE *f)
Write cpp file.
void write_create_message_method_cpp(FILE *f)
Write create_message() method to cpp file.
void write_message_ctor_dtor_h(FILE *f, std::string is, std::string classname, std::vector< InterfaceField > fields)
Write constructor and destructor for message to h file.
void write_message_clone_method_cpp(FILE *f, std::string classname)
Write message clone method.
void write_h(FILE *f)
Write h file.
void write_message_clone_method_h(FILE *f, std::string is)
Write message clone method header.
std::list< std::pair< std::string, std::string > > RefList
Reference list.
Definition: pseudomap.h:35
void write_ctor_dtor_cpp(FILE *f, std::string classname, std::string super_class, std::string inclusion_prefix, std::vector< InterfaceField > fields, std::vector< InterfaceMessage > messages)
Write constructor and destructor to cpp file.
void write_ctor_dtor_h(FILE *f, std::string is, std::string classname)
Write constructor and destructor to h file.
void write_enum_maps_h(FILE *f)
Write enum maps to header.
void write_methods_h(FILE *f, std::string is, std::vector< InterfaceField > fields)
Write methods to h file.
void write_enum_constants_tostring_cpp(FILE *f)
Write enum constant tostring methods to cpp file.
void write_copy_value_method_cpp(FILE *f)
Write copy_value() method to CPP file.
void write_basemethods_cpp(FILE *f)
Write base methods.
void write_messages_h(FILE *f)
Write messages to h file.
~CppInterfaceGenerator()
Destructor.
void write_methods_cpp(FILE *f, std::string interface_classname, std::string classname, std::vector< InterfaceField > fields, std::string inclusion_prefix, bool write_data_changed)
Write methods to cpp file.
void write_enum_tostring_method_cpp(FILE *f)
Write enum_tostring() method to CPP file.
void write_header(FILE *f, std::string filename)
Write header to file.
void write_constants_cpp(FILE *f)
Write constants to cpp file.