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