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 __attribute__((packed)) {\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 + "::", false);
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_) == 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, "%s%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(\"%s\")\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  classname.c_str());
902 
903  fprintf(f,
904  " data_size = m->data_size;\n"
905  " data_ptr = malloc(data_size);\n"
906  " memcpy(data_ptr, m->data_ptr, data_size);\n"
907  " data = (%s_data_t *)data_ptr;\n"
908  " data_ts = (message_data_ts_t *)data_ptr;\n",
909  classname.c_str());
910 
911  fprintf(f, "}\n\n");
912 }
913 
914 /** Write methods to cpp file.
915  * @param f file to write to
916  * @param interface_classname name of the interface class
917  * @param classname name of class (can be interface or message)
918  * @param fields fields
919  * @param inclusion_prefix used if class is included in another class.
920  * @param write_data_changed if true writes code that sets the interface's
921  * data_changed flag. Set to true for interface methods, false for message
922  * methods.
923  */
924 void
926  std::string interface_classname,
927  std::string classname,
928  std::vector<InterfaceField> fields,
929  std::string inclusion_prefix,
930  bool write_data_changed)
931 {
932  fprintf(f, "/* Methods */\n");
933  for (vector<InterfaceField>::iterator i = fields.begin(); i != fields.end(); ++i) {
934  fprintf(f,
935  "/** Get %s value.\n"
936  " * %s\n"
937  " * @return %s value\n"
938  " */\n"
939  "%s%s\n"
940  "%s%s::%s%s() const\n"
941  "{\n"
942  " return %sdata->%s;\n"
943  "}\n\n",
944  (*i).getName().c_str(),
945  (*i).getComment().c_str(),
946  (*i).getName().c_str(),
947  (*i).isEnumType() ? (interface_classname + "::").c_str() : "",
948  (*i).getAccessType().c_str(),
949  inclusion_prefix.c_str(),
950  classname.c_str(),
951  (((*i).getType() == "bool") ? "is_" : ""),
952  (*i).getName().c_str(),
953  (*i).isEnumType()
954  ? (std::string("(") + interface_classname + "::" + i->getAccessType() + ")").c_str()
955  : "",
956  (*i).getName().c_str());
957 
958  if ((i->getLengthValue() > 0) && (i->getType() != "string")) {
959  fprintf(
960  f,
961  "/** Get %s value at given index.\n"
962  " * %s\n"
963  " * @param index index of value\n"
964  " * @return %s value\n"
965  " * @exception Exception thrown if index is out of bounds\n"
966  " */\n"
967  "%s%s\n"
968  "%s%s::%s%s(unsigned int index) const\n"
969  "{\n"
970  " if (index > %s) {\n"
971  " throw Exception(\"Index value %%u out of bounds (0..%s)\", index);\n"
972  " }\n"
973  " return %sdata->%s[index];\n"
974  "}\n\n",
975  (*i).getName().c_str(),
976  (*i).getComment().c_str(),
977  (*i).getName().c_str(),
978  (*i).isEnumType() ? (interface_classname + "::").c_str() : "",
979  (*i).getPlainAccessType().c_str(),
980  inclusion_prefix.c_str(),
981  classname.c_str(),
982  (((*i).getType() == "bool") ? "is_" : ""),
983  (*i).getName().c_str(),
984  i->getLength().c_str(),
985  i->getLength().c_str(),
986  (*i).isEnumType()
987  ? (std::string("(") + interface_classname + "::" + i->getPlainAccessType() + ")").c_str()
988  : "",
989  (*i).getName().c_str());
990  }
991 
992  fprintf(f,
993  "/** Get maximum length of %s value.\n"
994  " * @return length of %s value, can be length of the array or number of \n"
995  " * maximum number of characters for a string\n"
996  " */\n"
997  "size_t\n"
998  "%s%s::maxlenof_%s() const\n"
999  "{\n"
1000  " return %s;\n"
1001  "}\n\n",
1002  i->getName().c_str(),
1003  i->getName().c_str(),
1004  inclusion_prefix.c_str(),
1005  classname.c_str(),
1006  i->getName().c_str(),
1007  i->getLengthValue() > 0 ? i->getLength().c_str() : "1");
1008 
1009  fprintf(f,
1010  "/** Set %s value.\n"
1011  " * %s\n"
1012  " * @param new_%s new %s value\n"
1013  " */\n"
1014  "void\n"
1015  "%s%s::set_%s(const %s new_%s)\n"
1016  "{\n",
1017  (*i).getName().c_str(),
1018  (*i).getComment().c_str(),
1019  (*i).getName().c_str(),
1020  (*i).getName().c_str(),
1021  inclusion_prefix.c_str(),
1022  classname.c_str(),
1023  (*i).getName().c_str(),
1024  (*i).getAccessType().c_str(),
1025  (*i).getName().c_str());
1026  if ((*i).getType() == "string") {
1027  fprintf(f,
1028  " strncpy(data->%s, new_%s, sizeof(data->%s)-1);\n"
1029  " data->%s[sizeof(data->%s)-1] = 0;\n",
1030  (*i).getName().c_str(),
1031  (*i).getName().c_str(),
1032  (*i).getName().c_str(),
1033  (*i).getName().c_str(),
1034  (*i).getName().c_str());
1035  } else if ((*i).getLength() != "") {
1036  fprintf(f,
1037  " memcpy(data->%s, new_%s, sizeof(%s) * %s);\n",
1038  (*i).getName().c_str(),
1039  (*i).getName().c_str(),
1040  (*i).getPlainAccessType().c_str(),
1041  (*i).getLength().c_str());
1042  } else {
1043  fprintf(f, " data->%s = new_%s;\n", (*i).getName().c_str(), (*i).getName().c_str());
1044  }
1045  fprintf(f, "%s}\n\n", write_data_changed ? " data_changed = true;\n" : "");
1046 
1047  if (((*i).getType() != "string") && ((*i).getLengthValue() > 0)) {
1048  fprintf(f,
1049  "/** Set %s value at given index.\n"
1050  " * %s\n"
1051  " * @param new_%s new %s value\n"
1052  " * @param index index for of the value\n"
1053  " */\n"
1054  "void\n"
1055  "%s%s::set_%s(unsigned int index, const %s new_%s)\n"
1056  "{\n"
1057  " if (index > %s) {\n"
1058  " throw Exception(\"Index value %%u out of bounds (0..%s)\", index);\n"
1059  " }\n"
1060  " data->%s[index] = new_%s;\n"
1061  "%s"
1062  "}\n",
1063  (*i).getName().c_str(),
1064  (*i).getComment().c_str(),
1065  (*i).getName().c_str(),
1066  (*i).getName().c_str(),
1067  inclusion_prefix.c_str(),
1068  classname.c_str(),
1069  (*i).getName().c_str(),
1070  (*i).getPlainAccessType().c_str(),
1071  i->getName().c_str(),
1072  i->getLength().c_str(),
1073  i->getLength().c_str(),
1074  i->getName().c_str(),
1075  i->getName().c_str(),
1076  write_data_changed ? " data_changed = true;\n" : "");
1077  }
1078  }
1079 }
1080 
1081 /** Write methods to cpp file including pseudo maps.
1082  * @param f file to write to
1083  * @param interface_classname name of the interface class
1084  * @param classname name of class (can be interface or message)
1085  * @param fields fields
1086  * @param pseudo_maps pseudo maps
1087  * @param inclusion_prefix used if class is included in another class.
1088  */
1089 void
1091  std::string interface_classname,
1092  std::string classname,
1093  std::vector<InterfaceField> fields,
1094  std::vector<InterfacePseudoMap> pseudo_maps,
1095  std::string inclusion_prefix)
1096 {
1097  write_methods_cpp(f, interface_classname, classname, fields, inclusion_prefix, true);
1098 
1099  for (vector<InterfacePseudoMap>::iterator i = pseudo_maps.begin(); i != pseudo_maps.end(); ++i) {
1100  fprintf(f,
1101  "/** Get %s value.\n"
1102  " * %s\n"
1103  " * @param key key of the value\n"
1104  " * @return %s value\n"
1105  " */\n"
1106  "%s\n"
1107  "%s%s::%s(const %s key) const\n"
1108  "{\n",
1109  (*i).getName().c_str(),
1110  (*i).getComment().c_str(),
1111  (*i).getName().c_str(),
1112  (*i).getType().c_str(),
1113  inclusion_prefix.c_str(),
1114  classname.c_str(),
1115  (*i).getName().c_str(),
1116  (*i).getKeyType().c_str());
1117 
1118  InterfacePseudoMap::RefList & reflist = i->getRefList();
1119  InterfacePseudoMap::RefList::iterator paref;
1120  bool first = true;
1121  for (paref = reflist.begin(); paref != reflist.end(); ++paref) {
1122  fprintf(f,
1123  " %sif (key == %s) {\n"
1124  " return data->%s;\n",
1125  first ? "" : "} else ",
1126  paref->second.c_str(),
1127  paref->first.c_str());
1128  first = false;
1129  }
1130  fprintf(f,
1131  " } else {\n"
1132  " throw Exception(\"Invalid key, cannot retrieve value\");\n"
1133  " }\n"
1134  "}\n\n");
1135 
1136  fprintf(f,
1137  "/** Set %s value.\n"
1138  " * %s\n"
1139  " * @param key key of the value\n"
1140  " * @param new_value new value\n"
1141  " */\n"
1142  "void\n"
1143  "%s%s::set_%s(const %s key, const %s new_value)\n"
1144  "{\n",
1145  (*i).getName().c_str(),
1146  (*i).getComment().c_str(),
1147  inclusion_prefix.c_str(),
1148  classname.c_str(),
1149  (*i).getName().c_str(),
1150  (*i).getKeyType().c_str(),
1151  (*i).getType().c_str());
1152 
1153  first = true;
1154  for (paref = reflist.begin(); paref != reflist.end(); ++paref) {
1155  fprintf(f,
1156  " %sif (key == %s) {\n"
1157  " data->%s = new_value;\n",
1158  first ? "" : "} else ",
1159  paref->second.c_str(),
1160  paref->first.c_str());
1161  first = false;
1162  }
1163 
1164  fprintf(f,
1165  " }\n"
1166  "}\n\n");
1167  }
1168 }
1169 
1170 /** Write methods to h file.
1171  * @param f file to write to
1172  * @param is indentation space.
1173  * @param fields fields to write accessor methods for.
1174  */
1175 void
1177  std::string /* indent space */ is,
1178  std::vector<InterfaceField> fields)
1179 {
1180  fprintf(f, "%s/* Methods */\n", is.c_str());
1181  for (vector<InterfaceField>::iterator i = fields.begin(); i != fields.end(); ++i) {
1182  fprintf(f,
1183  "%s%s %s%s() const;\n",
1184  is.c_str(),
1185  (*i).getAccessType().c_str(),
1186  (((*i).getType() == "bool") ? "is_" : ""),
1187  (*i).getName().c_str());
1188 
1189  if ((i->getLengthValue() > 0) && (i->getType() != "string")) {
1190  fprintf(f,
1191  "%s%s %s%s(unsigned int index) const;\n"
1192  "%svoid set_%s(unsigned int index, const %s new_%s);\n",
1193  is.c_str(),
1194  i->getPlainAccessType().c_str(),
1195  (((*i).getType() == "bool") ? "is_" : ""),
1196  (*i).getName().c_str(),
1197  is.c_str(),
1198  (*i).getName().c_str(),
1199  i->getPlainAccessType().c_str(),
1200  i->getName().c_str());
1201  }
1202 
1203  fprintf(f,
1204  "%svoid set_%s(const %s new_%s);\n"
1205  "%ssize_t maxlenof_%s() const;\n",
1206  is.c_str(),
1207  (*i).getName().c_str(),
1208  i->getAccessType().c_str(),
1209  i->getName().c_str(),
1210  is.c_str(),
1211  i->getName().c_str());
1212  }
1213 }
1214 
1215 /** Write methods to h file.
1216  * @param f file to write to
1217  * @param is indentation space.
1218  * @param fields fields to write accessor methods for.
1219  * @param pseudo_maps pseudo maps
1220  */
1221 void
1223  std::string /* indent space */ is,
1224  std::vector<InterfaceField> fields,
1225  std::vector<InterfacePseudoMap> pseudo_maps)
1226 {
1227  write_methods_h(f, is, fields);
1228 
1229  for (vector<InterfacePseudoMap>::iterator i = pseudo_maps.begin(); i != pseudo_maps.end(); ++i) {
1230  fprintf(f,
1231  "%s%s %s(%s key) const;\n"
1232  "%svoid set_%s(const %s key, const %s new_value);\n",
1233  is.c_str(),
1234  (*i).getType().c_str(),
1235  (*i).getName().c_str(),
1236  (*i).getKeyType().c_str(),
1237  is.c_str(),
1238  (*i).getName().c_str(),
1239  i->getKeyType().c_str(),
1240  i->getType().c_str());
1241  }
1242 }
1243 
1244 /** Write base methods header entries.
1245  * @param f file to write to
1246  * @param is indentation string
1247  */
1248 void
1250 {
1251  fprintf(f,
1252  "%svirtual Message * create_message(const char *type) const;\n\n"
1253  "%svirtual void copy_values(const Interface *other);\n"
1254  "%svirtual const char * enum_tostring(const char *enumtype, int val) const;\n",
1255  is.c_str(),
1256  is.c_str(),
1257  is.c_str());
1258 }
1259 
1260 /** Write h file.
1261  * @param f file to write to
1262  */
1263 void
1265 {
1266  write_header(f, filename_h);
1267  write_deflector(f);
1268 
1269  fprintf(f,
1270  "#include <interface/interface.h>\n"
1271  "#include <interface/message.h>\n"
1272  "#include <interface/field_iterator.h>\n\n"
1273  "namespace fawkes {\n\n"
1274  "class %s : public Interface\n"
1275  "{\n"
1276  " /// @cond INTERNALS\n"
1277  " INTERFACE_MGMT_FRIENDS(%s)\n"
1278  " /// @endcond\n"
1279  " public:\n",
1280  class_name.c_str(),
1281  class_name.c_str());
1282 
1283  write_constants_h(f);
1284 
1285  fprintf(f, " private:\n");
1286 
1287  write_struct(f, class_name + "_data_t", " ", data_fields);
1288 
1289  fprintf(f, " %s_data_t *data;\n\n", class_name.c_str());
1290 
1291  write_enum_maps_h(f);
1292 
1293  fprintf(f, " public:\n");
1294 
1295  write_messages_h(f);
1296  fprintf(f, " private:\n");
1297  write_ctor_dtor_h(f, " ", class_name);
1298  fprintf(f, " public:\n");
1299  write_methods_h(f, " ", data_fields, pseudo_maps);
1300  write_basemethods_h(f, " ");
1301  fprintf(f, "\n};\n\n} // end namespace fawkes\n\n#endif\n");
1302 }
1303 
1304 /** Generator cpp and h files.
1305  */
1306 void
1308 {
1309  char timestring[26]; // 26 is mentioned in man asctime_r
1310  struct tm timestruct;
1311  time_t t = time(NULL);
1312  localtime_r(&t, &timestruct);
1313  asctime_r(&timestruct, timestring);
1314  gendate = timestring;
1315 
1316  FILE *cpp;
1317  FILE *h;
1318 
1319  cpp = fopen(string(dir + filename_cpp).c_str(), "w");
1320  h = fopen(string(dir + filename_h).c_str(), "w");
1321 
1322  if (cpp == NULL) {
1323  printf("Cannot open cpp file %s%s\n", dir.c_str(), filename_cpp.c_str());
1324  }
1325  if (h == NULL) {
1326  printf("Cannot open h file %s%s\n", dir.c_str(), filename_h.c_str());
1327  }
1328 
1329  write_cpp(cpp);
1330  write_h(h);
1331 
1332  fclose(cpp);
1333  fclose(h);
1334 }
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.
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.