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
35using 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 */
125void
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 */
157void
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 */
171void
172CppInterfaceGenerator::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 */
208void
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 */
218void
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());
241 write_ctor_dtor_cpp(f, class_name, "Interface", "", data_fields, messages);
243 write_methods_cpp(f, class_name, class_name, data_fields, pseudo_maps, "");
246
248
249 fprintf(f, "\n} // end namespace fawkes\n");
250}
251
252/** Write management functions.
253 * @param f file to write to
254 */
255void
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 */
268void
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 */
292void
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 */
326void
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 */
368void
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
383
384 fprintf(f, " public:\n");
385 write_message_ctor_dtor_h(f, " ", (*i).getName(), (*i).getFields());
386 write_methods_h(f, " ", (*i).getFields());
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 */
396void
398{
399 fprintf(f, "/* =========== messages =========== */\n");
400 for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
401 fprintf(f,
402 "/** @class %s::%s <interfaces/%s>\n"
403 " * %s Fawkes BlackBoard Interface Message.\n"
404 " * %s\n"
405 " */\n\n\n",
406 class_name.c_str(),
407 (*i).getName().c_str(),
408 filename_h.c_str(),
409 (*i).getName().c_str(),
410 (*i).getComment().c_str());
411
412 write_message_ctor_dtor_cpp(f, (*i).getName(), "Message", class_name + "::", (*i).getFields());
413 write_methods_cpp(f, class_name, (*i).getName(), (*i).getFields(), class_name + "::");
414 write_message_clone_method_cpp(f, (class_name + "::" + (*i).getName()).c_str());
415 }
416 fprintf(f,
417 "/** Check if message is valid and can be enqueued.\n"
418 " * @param message Message to check\n"
419 " * @return true if the message is valid, false otherwise.\n"
420 " */\n"
421 "bool\n"
422 "%s::message_valid(const Message *message) const\n"
423 "{\n",
424 class_name.c_str());
425 unsigned int n = 0;
426 for (vector<InterfaceMessage>::iterator i = messages.begin(); i != messages.end(); ++i) {
427 fprintf(f,
428 " const %s *m%u = dynamic_cast<const %s *>(message);\n"
429 " if ( m%u != NULL ) {\n"
430 " return true;\n"
431 " }\n",
432 (*i).getName().c_str(),
433 n,
434 (*i).getName().c_str(),
435 n);
436 ++n;
437 }
438 fprintf(f,
439 " return false;\n"
440 "}\n\n");
441}
442
443/** Write create_message() method to cpp file.
444 * @param f file to write to
445 */
446void
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 */
484void
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 */
511void
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 */
538void
540{
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 */
551void
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 */
571void
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 */
602void
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 */
612void
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 */
633void
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 */
656void
657CppInterfaceGenerator::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 */
721void
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
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 */
780void
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
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
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 */
920void
922 std::string interface_classname,
923 std::string classname,
924 std::vector<InterfaceField> fields,
925 std::string inclusion_prefix)
926{
927 fprintf(f, "/* Methods */\n");
928 for (vector<InterfaceField>::iterator i = fields.begin(); i != fields.end(); ++i) {
929 fprintf(f,
930 "/** Get %s value.\n"
931 " * %s\n"
932 " * @return %s value\n"
933 " */\n"
934 "%s%s\n"
935 "%s%s::%s%s() const\n"
936 "{\n"
937 " return %sdata->%s;\n"
938 "}\n\n",
939 (*i).getName().c_str(),
940 (*i).getComment().c_str(),
941 (*i).getName().c_str(),
942 (*i).isEnumType() ? (interface_classname + "::").c_str() : "",
943 (*i).getAccessType().c_str(),
944 inclusion_prefix.c_str(),
945 classname.c_str(),
946 (((*i).getType() == "bool") ? "is_" : ""),
947 (*i).getName().c_str(),
948 (*i).isEnumType()
949 ? (std::string("(") + interface_classname + "::" + i->getAccessType() + ")").c_str()
950 : "",
951 (*i).getName().c_str());
952
953 if ((i->getLengthValue() > 0) && (i->getType() != "string")) {
954 fprintf(
955 f,
956 "/** Get %s value at given index.\n"
957 " * %s\n"
958 " * @param index index of value\n"
959 " * @return %s value\n"
960 " * @exception Exception thrown if index is out of bounds\n"
961 " */\n"
962 "%s%s\n"
963 "%s%s::%s%s(unsigned int index) const\n"
964 "{\n"
965 " if (index > %s) {\n"
966 " throw Exception(\"Index value %%u out of bounds (0..%s)\", index);\n"
967 " }\n"
968 " return %sdata->%s[index];\n"
969 "}\n\n",
970 (*i).getName().c_str(),
971 (*i).getComment().c_str(),
972 (*i).getName().c_str(),
973 (*i).isEnumType() ? (interface_classname + "::").c_str() : "",
974 (*i).getPlainAccessType().c_str(),
975 inclusion_prefix.c_str(),
976 classname.c_str(),
977 (((*i).getType() == "bool") ? "is_" : ""),
978 (*i).getName().c_str(),
979 i->getMaxIdx().c_str(),
980 i->getMaxIdx().c_str(),
981 (*i).isEnumType()
982 ? (std::string("(") + interface_classname + "::" + i->getPlainAccessType() + ")").c_str()
983 : "",
984 (*i).getName().c_str());
985 }
986
987 fprintf(f,
988 "/** Get maximum length of %s value.\n"
989 " * @return length of %s value, can be length of the array or number of \n"
990 " * maximum number of characters for a string\n"
991 " */\n"
992 "size_t\n"
993 "%s%s::maxlenof_%s() const\n"
994 "{\n"
995 " return %s;\n"
996 "}\n\n",
997 i->getName().c_str(),
998 i->getName().c_str(),
999 inclusion_prefix.c_str(),
1000 classname.c_str(),
1001 i->getName().c_str(),
1002 i->getLengthValue() > 0 ? i->getLength().c_str() : "1");
1003
1004 fprintf(f,
1005 "/** Set %s value.\n"
1006 " * %s\n"
1007 " * @param new_%s new %s value\n"
1008 " */\n"
1009 "void\n"
1010 "%s%s::set_%s(const %s new_%s)\n"
1011 "{\n",
1012 (*i).getName().c_str(),
1013 (*i).getComment().c_str(),
1014 (*i).getName().c_str(),
1015 (*i).getName().c_str(),
1016 inclusion_prefix.c_str(),
1017 classname.c_str(),
1018 (*i).getName().c_str(),
1019 (*i).getAccessType().c_str(),
1020 (*i).getName().c_str());
1021
1022 fprintf(f,
1023 " set_field(data->%s, new_%s);\n"
1024 "}\n\n",
1025 (*i).getName().c_str(),
1026 (*i).getName().c_str());
1027
1028 if (((*i).getType() != "string") && ((*i).getLengthValue() > 0)) {
1029 fprintf(f,
1030 "/** Set %s value at given index.\n"
1031 " * %s\n"
1032 " * @param new_%s new %s value\n"
1033 " * @param index index for of the value\n"
1034 " */\n"
1035 "void\n"
1036 "%s%s::set_%s(unsigned int index, const %s new_%s)\n"
1037 "{\n"
1038 " set_field(data->%s, index, new_%s);\n"
1039 "}\n",
1040 (*i).getName().c_str(),
1041 (*i).getComment().c_str(),
1042 (*i).getName().c_str(),
1043 (*i).getName().c_str(),
1044 inclusion_prefix.c_str(),
1045 classname.c_str(),
1046 (*i).getName().c_str(),
1047 (*i).getPlainAccessType().c_str(),
1048 i->getName().c_str(),
1049 i->getName().c_str(),
1050 i->getName().c_str());
1051 }
1052 }
1053}
1054
1055/** Write methods to cpp file including pseudo maps.
1056 * @param f file to write to
1057 * @param interface_classname name of the interface class
1058 * @param classname name of class (can be interface or message)
1059 * @param fields fields
1060 * @param pseudo_maps pseudo maps
1061 * @param inclusion_prefix used if class is included in another class.
1062 */
1063void
1065 std::string interface_classname,
1066 std::string classname,
1067 std::vector<InterfaceField> fields,
1068 std::vector<InterfacePseudoMap> pseudo_maps,
1069 std::string inclusion_prefix)
1070{
1071 write_methods_cpp(f, interface_classname, classname, fields, inclusion_prefix);
1072
1073 for (vector<InterfacePseudoMap>::iterator i = pseudo_maps.begin(); i != pseudo_maps.end(); ++i) {
1074 fprintf(f,
1075 "/** Get %s value.\n"
1076 " * %s\n"
1077 " * @param key key of the value\n"
1078 " * @return %s value\n"
1079 " */\n"
1080 "%s\n"
1081 "%s%s::%s(const %s key) const\n"
1082 "{\n",
1083 (*i).getName().c_str(),
1084 (*i).getComment().c_str(),
1085 (*i).getName().c_str(),
1086 (*i).getType().c_str(),
1087 inclusion_prefix.c_str(),
1088 classname.c_str(),
1089 (*i).getName().c_str(),
1090 (*i).getKeyType().c_str());
1091
1092 InterfacePseudoMap::RefList & reflist = i->getRefList();
1093 InterfacePseudoMap::RefList::iterator paref;
1094 bool first = true;
1095 for (paref = reflist.begin(); paref != reflist.end(); ++paref) {
1096 fprintf(f,
1097 " %sif (key == %s) {\n"
1098 " return data->%s;\n",
1099 first ? "" : "} else ",
1100 paref->second.c_str(),
1101 paref->first.c_str());
1102 first = false;
1103 }
1104 fprintf(f,
1105 " } else {\n"
1106 " throw Exception(\"Invalid key, cannot retrieve value\");\n"
1107 " }\n"
1108 "}\n\n");
1109
1110 fprintf(f,
1111 "/** Set %s value.\n"
1112 " * %s\n"
1113 " * @param key key of the value\n"
1114 " * @param new_value new value\n"
1115 " */\n"
1116 "void\n"
1117 "%s%s::set_%s(const %s key, const %s new_value)\n"
1118 "{\n",
1119 (*i).getName().c_str(),
1120 (*i).getComment().c_str(),
1121 inclusion_prefix.c_str(),
1122 classname.c_str(),
1123 (*i).getName().c_str(),
1124 (*i).getKeyType().c_str(),
1125 (*i).getType().c_str());
1126
1127 first = true;
1128 for (paref = reflist.begin(); paref != reflist.end(); ++paref) {
1129 fprintf(f,
1130 " %sif (key == %s) {\n"
1131 " data->%s = new_value;\n",
1132 first ? "" : "} else ",
1133 paref->second.c_str(),
1134 paref->first.c_str());
1135 first = false;
1136 }
1137
1138 fprintf(f,
1139 " }\n"
1140 "}\n\n");
1141 }
1142}
1143
1144/** Write methods to h file.
1145 * @param f file to write to
1146 * @param is indentation space.
1147 * @param fields fields to write accessor methods for.
1148 */
1149void
1151 std::string /* indent space */ is,
1152 std::vector<InterfaceField> fields)
1153{
1154 fprintf(f, "%s/* Methods */\n", is.c_str());
1155 for (vector<InterfaceField>::iterator i = fields.begin(); i != fields.end(); ++i) {
1156 fprintf(f,
1157 "%s%s %s%s() const;\n",
1158 is.c_str(),
1159 (*i).getAccessType().c_str(),
1160 (((*i).getType() == "bool") ? "is_" : ""),
1161 (*i).getName().c_str());
1162
1163 if ((i->getLengthValue() > 0) && (i->getType() != "string")) {
1164 fprintf(f,
1165 "%s%s %s%s(unsigned int index) const;\n"
1166 "%svoid set_%s(unsigned int index, const %s new_%s);\n",
1167 is.c_str(),
1168 i->getPlainAccessType().c_str(),
1169 (((*i).getType() == "bool") ? "is_" : ""),
1170 (*i).getName().c_str(),
1171 is.c_str(),
1172 (*i).getName().c_str(),
1173 i->getPlainAccessType().c_str(),
1174 i->getName().c_str());
1175 }
1176
1177 fprintf(f,
1178 "%svoid set_%s(const %s new_%s);\n"
1179 "%ssize_t maxlenof_%s() const;\n",
1180 is.c_str(),
1181 (*i).getName().c_str(),
1182 i->getAccessType().c_str(),
1183 i->getName().c_str(),
1184 is.c_str(),
1185 i->getName().c_str());
1186 }
1187}
1188
1189/** Write methods to h file.
1190 * @param f file to write to
1191 * @param is indentation space.
1192 * @param fields fields to write accessor methods for.
1193 * @param pseudo_maps pseudo maps
1194 */
1195void
1197 std::string /* indent space */ is,
1198 std::vector<InterfaceField> fields,
1199 std::vector<InterfacePseudoMap> pseudo_maps)
1200{
1201 write_methods_h(f, is, fields);
1202
1203 for (vector<InterfacePseudoMap>::iterator i = pseudo_maps.begin(); i != pseudo_maps.end(); ++i) {
1204 fprintf(f,
1205 "%s%s %s(%s key) const;\n"
1206 "%svoid set_%s(const %s key, const %s new_value);\n",
1207 is.c_str(),
1208 (*i).getType().c_str(),
1209 (*i).getName().c_str(),
1210 (*i).getKeyType().c_str(),
1211 is.c_str(),
1212 (*i).getName().c_str(),
1213 i->getKeyType().c_str(),
1214 i->getType().c_str());
1215 }
1216}
1217
1218/** Write base methods header entries.
1219 * @param f file to write to
1220 * @param is indentation string
1221 */
1222void
1224{
1225 fprintf(f,
1226 "%svirtual Message * create_message(const char *type) const;\n\n"
1227 "%svirtual void copy_values(const Interface *other);\n"
1228 "%svirtual const char * enum_tostring(const char *enumtype, int val) const;\n",
1229 is.c_str(),
1230 is.c_str(),
1231 is.c_str());
1232}
1233
1234/** Write h file.
1235 * @param f file to write to
1236 */
1237void
1239{
1240 write_header(f, filename_h);
1241 write_deflector(f);
1242
1243 fprintf(f,
1244 "#include <interface/interface.h>\n"
1245 "#include <interface/message.h>\n"
1246 "#include <interface/field_iterator.h>\n\n"
1247 "namespace fawkes {\n\n"
1248 "class %s : public Interface\n"
1249 "{\n"
1250 " /// @cond INTERNALS\n"
1251 " INTERFACE_MGMT_FRIENDS(%s)\n"
1252 " /// @endcond\n"
1253 " public:\n",
1254 class_name.c_str(),
1255 class_name.c_str());
1256
1258
1259 fprintf(f, " private:\n");
1260
1261 write_struct(f, class_name + "_data_t", " ", data_fields);
1262
1263 fprintf(f, " %s_data_t *data;\n\n", class_name.c_str());
1264
1266
1267 fprintf(f, " public:\n");
1268
1270 fprintf(f, " private:\n");
1271 write_ctor_dtor_h(f, " ", class_name);
1272 fprintf(f, " public:\n");
1273 write_methods_h(f, " ", data_fields, pseudo_maps);
1274 write_basemethods_h(f, " ");
1275 fprintf(f, "\n};\n\n} // end namespace fawkes\n\n#endif\n");
1276}
1277
1278/** Generator cpp and h files.
1279 */
1280void
1282{
1283 char timestring[26]; // 26 is mentioned in man asctime_r
1284 struct tm timestruct;
1285 time_t t = time(NULL);
1286 localtime_r(&t, &timestruct);
1287 asctime_r(&timestruct, timestring);
1288 gendate = timestring;
1289
1290 FILE *cpp;
1291 FILE *h;
1292
1293 cpp = fopen(string(dir + filename_cpp).c_str(), "w");
1294 h = fopen(string(dir + filename_h).c_str(), "w");
1295
1296 if (cpp == NULL) {
1297 printf("Cannot open cpp file %s%s\n", dir.c_str(), filename_cpp.c_str());
1298 }
1299 if (h == NULL) {
1300 printf("Cannot open h file %s%s\n", dir.c_str(), filename_h.c_str());
1301 }
1302
1303 write_cpp(cpp);
1304 write_h(h);
1305
1306 fclose(cpp);
1307 fclose(h);
1308}
void write_ctor_dtor_h(FILE *f, std::string is, std::string classname)
Write constructor and destructor to h file.
void write_struct(FILE *f, std::string name, std::string is, std::vector< InterfaceField > fields)
Write optimized struct.
void write_basemethods_cpp(FILE *f)
Write base methods.
void write_management_funcs_cpp(FILE *f)
Write management functions.
void write_deflector(FILE *f)
Write header deflector.
void write_h(FILE *f)
Write h file.
void write_ctor_dtor_cpp(FILE *f, std::string classname, std::string super_class, std::string inclusion_prefix, std::vector< InterfaceField > fields, std::vector< InterfaceMessage > messages)
Write constructor and destructor to cpp file.
void generate()
Generator cpp and h files.
void write_basemethods_h(FILE *f, std::string is)
Write base methods header entries.
void write_message_ctor_dtor_cpp(FILE *f, std::string classname, std::string super_class, std::string inclusion_prefix, std::vector< InterfaceField > fields)
Write constructor and destructor for message to cpp file.
void write_methods_h(FILE *f, std::string is, std::vector< InterfaceField > fields)
Write methods to h file.
void write_message_clone_method_cpp(FILE *f, std::string classname)
Write message clone method.
void write_enum_tostring_method_cpp(FILE *f)
Write enum_tostring() method to CPP file.
void write_enum_map_population(FILE *f)
Write enum maps.
void write_constants_cpp(FILE *f)
Write constants to cpp file.
void write_copy_value_method_cpp(FILE *f)
Write copy_value() method to CPP file.
void write_add_fieldinfo_calls(FILE *f, std::vector< InterfaceField > &fields)
Write the add_fieldinfo() calls.
void write_cpp(FILE *f)
Write cpp file.
CppInterfaceGenerator(std::string directory, std::string interface_name, std::string config_basename, std::string author, std::string year, std::string creation_date, std::string data_comment, const unsigned char *hash, size_t hash_size, const std::vector< InterfaceConstant > &constants, const std::vector< InterfaceEnumConstant > &enum_constants, const std::vector< InterfaceField > &data_fields, const std::vector< InterfacePseudoMap > &pseudo_maps, const std::vector< InterfaceMessage > &messages)
Constructor.
void write_message_ctor_dtor_h(FILE *f, std::string is, std::string classname, std::vector< InterfaceField > fields)
Write constructor and destructor for message to h file.
void write_create_message_method_cpp(FILE *f)
Write create_message() method to cpp file.
void write_enum_constants_tostring_cpp(FILE *f)
Write enum constant tostring methods to cpp file.
void write_messages_h(FILE *f)
Write messages to h file.
void write_messages_cpp(FILE *f)
Write messages to cpp file.
void write_constants_h(FILE *f)
Write constants to h file.
~CppInterfaceGenerator()
Destructor.
void write_enum_maps_h(FILE *f)
Write enum maps to header.
void write_header(FILE *f, std::string filename)
Write header to file.
void write_methods_cpp(FILE *f, std::string interface_classname, std::string classname, std::vector< InterfaceField > fields, std::string inclusion_prefix)
Write methods to cpp file.
void write_message_clone_method_h(FILE *f, std::string is)
Write message clone method header.
std::list< std::pair< std::string, std::string > > RefList
Reference list.
Definition: pseudomap.h:35
static std::string to_upper(std::string str)
Convert string to all-uppercase string.