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