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