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