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 
35 using 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  */
49 PluginGenerator::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  */
89 void
90 PluginGenerator::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  */
122 void
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  */
149 void
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  */
159 void
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  */
196 void
198 {
199  write_header(f, _filename_thread_h);
200  write_deflector(f);
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  */
237 void
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  */
281 void
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  */
310 std::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  */
326 std::string
327 PluginGenerator::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  */
357 void
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 }
std::string format_class_name(std::string plugin_name, std::string append)
Format a lowercase plugin name to CamelCase class.
static std::string to_upper(std::string str)
Convert string to all-uppercase string.
void write_thread_h(FILE *f)
Write h file.
void write_thread_cpp(FILE *f)
Write cpp file.
void write_plugin_cpp(FILE *f)
Write plugin cpp file.
std::string replace_dash_w_undescore(std::string source)
Replace dash with underscore.
void write_makefile_header(FILE *f)
Write makefile header.
void generate()
Generator cpp and h files.
Base class for exceptions in Fawkes.
Definition: exception.h:35
void write_header(FILE *f, std::string filename)
Write header to file.
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.
~PluginGenerator()
Destructor.
void write_makefile(FILE *f)
Write Makefile.
void write_deflector(FILE *f)
Write header deflector.