Fawkes API Fawkes Development Version
plugin_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 "plugin_generator.h"
24
25#include <core/exception.h>
26#include <sys/stat.h>
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 PluginGenerator "plugin_generator.h
38 * Generate basic plugins from minimal input.
39 */
40
41/** Constructor.
42 * @param directory Directory where to create the files
43 * @param author Author of the plugin
44 * @param year Year of copyright
45 * @param creation_date Creation date of the plugin
46 * @param plugin_name Name of the plugin
47 * @param description Plugin description
48 */
49PluginGenerator::PluginGenerator(const std::string &directory,
50 const std::string &author,
51 const std::string &year,
52 const std::string &creation_date,
53 const std::string &plugin_name,
54 const std::string &description)
55: _dir(directory),
56 _author(author),
57 _year(year),
58 _creation_date(creation_date),
59 _plugin_name(plugin_name),
60 _description(description)
61{
62 if (_dir.find_last_of("/") != (_dir.length() - 1)) {
63 _dir += "/";
64 }
65
66 _filename_thread_cpp = plugin_name + "_thread.cpp";
67 _filename_thread_h = plugin_name + "_thread.h";
68 _filename_plugin_cpp = plugin_name + "_plugin.cpp";
69 _filename_makefile = "Makefile";
70
71 _plugin_name_underscore = replace_dash_w_undescore(_plugin_name);
72
73 _class_name_thread = format_class_name(_plugin_name_underscore, "Thread");
74 _class_name_plugin = format_class_name(_plugin_name_underscore, "Plugin");
75
76 _deflector =
77 "PLUGINS__" + fawkes::StringConversions::to_upper(_plugin_name_underscore) + "_THREAD_H_";
78}
79
80/** Destructor */
82{
83}
84
85/** Write header to file.
86 * @param f file to write to
87 * @param filename name of file
88 */
89void
90PluginGenerator::write_header(FILE *f, std::string filename)
91{
92 fprintf(f,
93 "\n/***************************************************************************\n"
94 " * %s - %s\n"
95 " *\n"
96 "%s%s"
97 " * Copyright %s %s\n"
98 " ****************************************************************************/\n\n"
99 "/* This program is free software; you can redistribute it and/or modify\n"
100 " * it under the terms of the GNU General Public License as published by\n"
101 " * the Free Software Foundation; either version 2 of the License, or\n"
102 " * (at your option) any later version.\n"
103 " *\n"
104 " * This program is distributed in the hope that it will be useful,\n"
105 " * but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
106 " * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
107 " * GNU Library General Public License for more details.\n"
108 " *\n"
109 " * Read the full text in the LICENSE.GPL file in the doc directory.\n"
110 " */\n\n",
111 filename.c_str(),
112 _plugin_name.c_str(),
113 (_creation_date.length() > 0) ? " * Created: " : "",
114 (_creation_date.length() > 0) ? _creation_date.c_str() : "",
115 _year.c_str(),
116 _author.c_str());
117}
118
119/** Write makefile header.
120 * @param f file to write to
121 */
122void
124{
125 fprintf(f,
126 "#*****************************************************************************\n"
127 "# Makefile Build System for Fawkes: %s Plugin\n"
128 "# -------------------\n"
129 "# Created on %s \n"
130 "# Copyright (C) %s by %s\n"
131 "#\n"
132 "#*****************************************************************************\n"
133 "#\n"
134 "# This program is free software; you can redistribute it and/or modify\n"
135 "# it under the terms of the GNU General Public License as published by\n"
136 "# the Free Software Foundation; either version 2 of the License, or\n"
137 "# (at your option) any later version.\n"
138 "#\n"
139 "#*****************************************************************************\n\n",
140 _plugin_name.c_str(),
141 _creation_date.c_str(),
142 _year.c_str(),
143 _author.c_str());
144}
145
146/** Write header deflector.
147 * @param f file to write to
148 */
149void
151{
152 fprintf(f, "#ifndef %s\n", _deflector.c_str());
153 fprintf(f, "#define %s\n\n", _deflector.c_str());
154}
155
156/** Write cpp file.
157 * @param f file to write to
158 */
159void
161{
162 write_header(f, _filename_thread_cpp);
163 fprintf(f,
164 "#include \"%s\"\n\n"
165 "using namespace fawkes;\n\n"
166 "/** @class %s '%s' \n"
167 " * %s\n"
168 " * @author %s\n"
169 " */\n\n",
170 _filename_thread_h.c_str(),
171 _class_name_thread.c_str(),
172 _filename_thread_h.c_str(),
173 _description.c_str(),
174 _author.c_str());
175 //Constructor
176 fprintf(f,
177 "/** Constructor. */\n"
178 "%s::%s()\n"
179 " : Thread(\"%s\", Thread::OPMODE_WAITFORWAKEUP),\n"
180 " BlockedTimingAspect(BlockedTimingAspect::WAKEUP_HOOK_ACT) \n{\n}\n\n",
181 //TODO support the other OPMODES
182 _class_name_thread.c_str(),
183 _class_name_thread.c_str(),
184 _class_name_thread.c_str());
185 //init
186 fprintf(f, "void\n%s::init()\n{\n}\n\n", _class_name_thread.c_str());
187 //loop
188 fprintf(f, "void\n%s::loop()\n{\n}\n\n", _class_name_thread.c_str());
189 //finalize
190 fprintf(f, "void\n%s::finalize()\n{\n}\n\n", _class_name_thread.c_str());
191}
192
193/** Write h file.
194 * @param f file to write to
195 */
196void
198{
199 write_header(f, _filename_thread_h);
201
202 fprintf(f,
203 "#include <core/threading/thread.h>\n"
204 "#include <aspect/blocked_timing.h>\n"
205 "#include <aspect/logging.h>\n"
206 "#include <aspect/blackboard.h>\n"
207 "#include <aspect/configurable.h>\n\n"
208
209 "namespace fawkes {\n"
210 " // add forward declarations here, e.g., interfaces\n"
211 "}\n\n"
212 "class %s \n"
213 ": public fawkes::Thread,\n"
214 " public fawkes::BlockedTimingAspect,\n"
215 " public fawkes::LoggingAspect,\n"
216 " public fawkes::ConfigurableAspect,\n"
217 " public fawkes::BlackBoardAspect\n"
218 "{\n\n"
219 " public:\n"
220 " %s();\n\n"
221 " virtual void init();\n"
222 " virtual void finalize();\n"
223 " virtual void loop();\n\n"
224 " /** Stub to see name in backtrace for easier debugging. @see Thread::run() */\n"
225 " protected: virtual void run() { Thread::run(); }\n\n"
226 " private:\n"
227 " //Define class member variables here\n",
228 _class_name_thread.c_str(),
229 _class_name_thread.c_str());
230
231 fprintf(f, "\n};\n\n\n#endif");
232}
233
234/** Write plugin cpp file.
235 * @param f file to write to
236 */
237void
239{
240 write_header(f, _filename_plugin_cpp);
241 fprintf(f,
242 "#include <core/plugin.h>\n\n"
243 "#include \"%s\"\n\n"
244 "using namespace fawkes;\n\n",
245 _filename_thread_h.c_str());
246 fprintf(f,
247 "/** @class %s \"%s\"\n"
248 " * %s\n"
249 " * @author %s\n"
250 " */\n",
251 _class_name_plugin.c_str(),
252 _filename_plugin_cpp.c_str(),
253 _description.c_str(),
254 _author.c_str());
255 fprintf(f,
256 "class %s : public fawkes::Plugin\n"
257 "{\n"
258 " public:\n"
259 " /** Constructor.\n"
260 " * @param config Fakwes configuration\n"
261 " */\n"
262 " %s(Configuration *config)\n"
263 " : Plugin(config)\n"
264 " {\n"
265 " thread_list.push_back(new %s());\n"
266 " }\n"
267 "};\n\n",
268 _class_name_plugin.c_str(),
269 _class_name_plugin.c_str(),
270 _class_name_thread.c_str());
271 fprintf(f,
272 "PLUGIN_DESCRIPTION(\"%s\")\n"
273 "EXPORT_PLUGIN(%s)",
274 _description.c_str(),
275 _class_name_plugin.c_str());
276}
277
278/** Write Makefile.
279 * @param f file to write to
280 */
281void
283{
285 std::string filename_plugin_o = _plugin_name + "_plugin.o";
286 std::string filename_thread_o = _plugin_name + "_thread.o";
287 fprintf(f,
288 "BASEDIR = ../../..\n"
289 "include $(BASEDIR)/etc/buildsys/config.mk\n\n"
290 "LIBS_%s = m fawkescore fawkesutils fawkesaspects fawkesbaseapp \\\n"
291 " fawkesblackboard fawkesinterface\n\n"
292 "OBJS_%s = %s %s\n\n",
293 _plugin_name_underscore.c_str(),
294 _plugin_name_underscore.c_str(),
295 filename_plugin_o.c_str(),
296 filename_thread_o.c_str());
297 fprintf(f,
298 "PLUGINS_all = $(PLUGINDIR)/%s.$(SOEXT)\n\n"
299 "OBJS_all = $(OBJS_%s)\n\n"
300 "include $(BUILDSYSDIR)/base.mk",
301 _plugin_name.c_str(),
302 _plugin_name.c_str());
303}
304
305/** Replace dash with underscore.
306 * Example: plugin-generator to plugin_generator
307 * @param source input string
308 * @return modified string
309 */
310std::string
312{
313 for (std::string::size_type i = 0; (i = source.find("-", i)) != std::string::npos;) {
314 source.replace(i, 1, "_");
315 i++;
316 }
317 return source;
318}
319
320/** Format a lowercase plugin name to CamelCase class.
321 * Example: plugin_name to PluginNameThread
322 * @param plugin_name name of plugin
323 * @param appendix class name appendix, e.g., Thread or Plugin
324 * @return class name matching the plugin name
325 */
326std::string
327PluginGenerator::format_class_name(std::string plugin_name, std::string appendix)
328{
329 std::string class_name;
330 //check if there is an underline in the plugin name
331 std::size_t underline_position = plugin_name.find('_');
332 if (underline_position != std::string::npos) {
333 //Eliminate underscores
334 std::istringstream stream(plugin_name);
335 std::string item;
336 std::vector<std::string> splitted;
337 while (std::getline(stream, item, '_')) {
338 splitted.push_back(item);
339 }
340 //camelcase the words
341 for (auto element : splitted) {
342 element[0] = std::toupper(element[0]);
343 class_name.append(element);
344 }
345 class_name.append(appendix);
346 } else {
347 //Use the name and append
348 plugin_name[0] = std::toupper(plugin_name[0]);
349 class_name.append(plugin_name);
350 class_name.append(appendix);
351 }
352 return class_name;
353}
354
355/** Generator cpp and h files.
356 */
357void
359{
360 FILE *thread_cpp;
361 FILE *thread_h;
362 FILE *plugin_cpp;
363 FILE *makefile;
364
365 struct stat info;
366
367 if (!(stat(_dir.c_str(), &info) == 0 && S_ISDIR(info.st_mode))) {
368 if (mkdir(_dir.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH) == -1) {
369 throw fawkes::Exception(errno, "Failed to generate plugin, cannot create directory");
370 }
371 }
372 thread_h = fopen(string(_dir + _filename_thread_h).c_str(), "w");
373 thread_cpp = fopen(string(_dir + _filename_thread_cpp).c_str(), "w");
374 plugin_cpp = fopen(string(_dir + _filename_plugin_cpp).c_str(), "w");
375 makefile = fopen(string(_dir + _filename_makefile).c_str(), "w");
376
377 if (thread_h == NULL) {
378 printf("Cannot open thread_h file %s%s\n", _dir.c_str(), _filename_thread_h.c_str());
379 }
380 if (thread_cpp == NULL) {
381 printf("Cannot open thread_cpp file %s%s\n", _dir.c_str(), _filename_thread_cpp.c_str());
382 }
383 if (plugin_cpp == NULL) {
384 printf("Cannot open plugin_cpp file %s%s\n", _dir.c_str(), _filename_plugin_cpp.c_str());
385 }
386 if (makefile == NULL) {
387 printf("Cannot open makefile %s%s\n", _dir.c_str(), _filename_makefile.c_str());
388 }
389
390 write_thread_cpp(thread_cpp);
391 write_thread_h(thread_h);
392 write_plugin_cpp(plugin_cpp);
393 write_makefile(makefile);
394
395 fclose(thread_cpp);
396 fclose(thread_h);
397 fclose(plugin_cpp);
398 fclose(makefile);
399
400 printf("Plugin %s successfully created!\n", _plugin_name.c_str());
401}
void write_header(FILE *f, std::string filename)
Write header to file.
void write_makefile(FILE *f)
Write Makefile.
void write_thread_cpp(FILE *f)
Write cpp file.
~PluginGenerator()
Destructor.
void write_makefile_header(FILE *f)
Write makefile header.
std::string replace_dash_w_undescore(std::string source)
Replace dash with underscore.
void generate()
Generator cpp and h files.
std::string format_class_name(std::string plugin_name, std::string append)
Format a lowercase plugin name to CamelCase class.
PluginGenerator(const std::string &directory, const std::string &author, const std::string &year, const std::string &creation_date, const std::string &plugin_name, const std::string &description)
Constructor.
void write_deflector(FILE *f)
Write header deflector.
void write_plugin_cpp(FILE *f)
Write plugin cpp file.
void write_thread_h(FILE *f)
Write h file.
Base class for exceptions in Fawkes.
Definition: exception.h:36
static std::string to_upper(std::string str)
Convert string to all-uppercase string.