Gyoto
GyotoRegister.h
Go to the documentation of this file.
1 /*
2  Copyright 2011-2025 Thibaut Paumard
3 
4  This file is part of Gyoto.
5 
6  Gyoto is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  Gyoto is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with Gyoto. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #ifndef __GyotoRegister_H_
21 #define __GyotoRegister_H_
22 
23 #include <string>
24 #include <glob.h>
25 #include <filesystem>
26 #include "GyotoSmartPointer.h"
27 
37 namespace Gyoto {
46  namespace Register {
47 
48  /* Documented below */
49  class Entry;
50 
65  void init( char const * pluglist = NULL );
66 
70  void list();
71  }
72 
92  void * loadPlugin( char const * const plugname, int nofail = 0);
93 
99  bool havePlugin(std::string plugname);
100 
112  void requirePlugin(std::string plugname, int nofail = 0);
113 
117  std::vector<std::string> pluginPath();
118 
122  void pluginPath(const std::vector<std::string> &v);
123 
124 }
125 
136  friend void Gyoto::Register::list();
137 protected:
138  std::string name_;
144  const std::string plugin_;
146 public:
150  Entry(std::string name,
152  Entry* next);
153  ~Entry();
154 
181  getSubcontractor(std::string name, std::string &plugin, int errmode=0);
182 
186  std::string name();
187 
191  std::string plugin();
192 
197 };
198 
247 #define GYOTO_GETSUBCONTRACTOR(space) \
248  Gyoto::space::Subcontractor_t* \
249  Gyoto::space::getSubcontractor(std::string name, \
250  std::vector<std::string> &plugin, \
251  int errmode) { \
252  std::vector<std::string> mandatory; \
253  std::vector<std::string> fallback; \
254  std::vector<std::string> plug_path(Gyoto::pluginPath()); \
255  GYOTO_DEBUG << "loading non-fallback plug-ins..." << std::endl; \
256  for (const auto &plg : plugin) { \
257  GYOTO_DEBUG_EXPR(plg); \
258  if (plg.rfind("fallback:", 0) != 0) { \
259  Gyoto::requirePlugin(plg); \
260  mandatory.emplace_back(plg); \
261  } \
262  else fallback.emplace_back(plg.substr(9)); \
263  } \
264  GYOTO_DEBUG << "found " << mandatory.size() \
265  << " mandatory plg-ins and "<< fallback.size() \
266  << " fallback plug-ins" << std::endl; \
267  GYOTO_DEBUG << \
268  "loading fallback plug-ins until the Register is not empty" \
269  << std::endl; \
270  for (const auto plg : fallback) { \
271  if (Gyoto::space::Register_) break; \
272  GYOTO_DEBUG_EXPR(plg); \
273  Gyoto::requirePlugin(plg, 2); \
274  } \
275  for (const auto &plg : fallback) { \
276  if (Gyoto::space::Register_) break; \
277  GYOTO_DEBUG_EXPR(plg); \
278  for (const auto &path : plug_path) { \
279  std::string pattern = (path + "libgyoto-" + plg) \
280  + "." GYOTO_PLUGIN_SFX; \
281  std::vector<std::string> files = \
282  Gyoto::glob(pattern); \
283  for (const auto &file : files) { \
284  GYOTO_DEBUG << "Trying " << file << std::endl; \
285  Gyoto::requirePlugin(file, 2); \
286  } \
287  } \
288  } \
289  if (!Gyoto::space::Register_) \
290  throwError("No " GYOTO_STRINGIFY(space) " kind registered!"); \
291  Gyoto::space::Subcontractor_t* sctr= NULL; \
292  GYOTO_DEBUG << "looking for " << name \
293  << " in non-fallback plug-ins..." << std::endl; \
294  for (auto & plg : mandatory) { \
295  GYOTO_DEBUG_EXPR(plg); \
296  sctr=(Gyoto::space::Subcontractor_t*)Gyoto::space::Register_ \
297  -> getSubcontractor(name, plg, 2); \
298  if (sctr) { \
299  GYOTO_DEBUG << "found " << name << " in plug-in " \
300  << plg << std::endl; \
301  return sctr; \
302  } \
303  } \
304  if (!mandatory.size()) { \
305  GYOTO_DEBUG << "looking for " << name \
306  << " in registered plug-ins..." << std::endl; \
307  std::string plg(""); \
308  sctr = (Gyoto::space::Subcontractor_t*)Gyoto::space::Register_ \
309  -> getSubcontractor(name, plg, 2); \
310  if (sctr){ \
311  GYOTO_DEBUG << "found " << name << " in plug-in " \
312  << plg << std::endl; \
313  plugin.emplace(plugin.begin(), plg); \
314  GYOTO_DEBUG << "added '" << plugin[0] \
315  << "' as item 0 of pluglist" << std::endl; \
316  return sctr; \
317  } else if (!fallback.size() && !errmode) \
318  throwError ("Kind not found in any plug-in: "+name); \
319  } \
320  GYOTO_DEBUG << "looking for " << name \
321  << " in fallback plug-ins..." << std::endl; \
322  /* try to load fallbacks directly */ \
323  for (auto &plg : fallback) { \
324  GYOTO_DEBUG_EXPR(plg); \
325  Gyoto::requirePlugin(plg, 2); \
326  sctr = (Gyoto::space::Subcontractor_t*)Gyoto::space::Register_ \
327  -> getSubcontractor(name, plg, 2); \
328  if (sctr) { \
329  GYOTO_DEBUG << "found " << name << " in plug-in " \
330  << plg << std::endl; \
331  return sctr; \
332  } \
333  } \
334  GYOTO_DEBUG << "looking for " << name \
335  << " in fallback plug-ins, " \
336  << "allowing for glob expansion..." << std::endl; \
337  for (const auto &plg : fallback) { \
338  /* try glob expansion on plg itself, may it is already a path \
339  with wildcards */ \
340  GYOTO_DEBUG_EXPR(plg); \
341  std::vector<std::string> files = Gyoto::glob(plg); \
342  for (auto &file : files) { \
343  GYOTO_DEBUG << "Trying " << file << std::endl; \
344  if (!std::filesystem::exists(file)) continue; \
345  Gyoto::requirePlugin(file, 2); \
346  sctr = (Gyoto::space::Subcontractor_t*)Gyoto::space::Register_ \
347  -> getSubcontractor(name, file, 2); \
348  if (sctr) { \
349  GYOTO_DEBUG << "found " << name << " in plug-in " \
350  << file << std::endl; \
351  return sctr; \
352  } \
353  } \
354  /* try glob expansion on <directory>/libgyoto-<plg>.so for every \
355  directory in the plug-in path */ \
356  for (const auto &path : plug_path) { \
357  std::string pattern = (path + "libgyoto-" + plg) \
358  + "." GYOTO_PLUGIN_SFX; \
359  files = Gyoto::glob(pattern); \
360  for (auto &file : files) { \
361  GYOTO_DEBUG << "Trying " << file << std::endl; \
362  if (!std::filesystem::exists(file)) continue; \
363  Gyoto::requirePlugin(file, 2); \
364  sctr=(Gyoto::space::Subcontractor_t*)Gyoto::space::Register_ \
365  -> getSubcontractor(name, file, 2); \
366  if (sctr) { \
367  GYOTO_DEBUG << "found " << name << " in plug-in " \
368  << file << std::endl; \
369  return sctr; \
370  } \
371  } \
372  } \
373  } \
374  GYOTO_DEBUG << name << " not found anywhere, error?" \
375  << std::endl; \
376  if (!errmode) \
377  throwError("Kind not found in the specified plug-ins: "+name); \
378  return sctr; \
379  }
380 
381 #endif
void * loadPlugin(char const *const plugname, int nofail=0)
Load a plugin by name.
Entry(std::string name, Gyoto::SmartPointee::Subcontractor_t *subcontractor, Entry *next)
Constructor.
Gyoto::SmartPointee::Subcontractor_t * getSubcontractor(std::string name, std::string &plugin, int errmode=0)
Get subcontractor for a given name.
std::string name_
Kind name for the entry, as found in the "kind" XML attribute.
Definition: GyotoRegister.h:138
Reference-counting pointers.
void Register(std::string name, Gyoto::Astrobj::Subcontractor_t *scp)
Make an Astrobj kind known to the Factory.
void init(char const *pluglist=NULL)
Initialise the various registers.
std::string plugin()
Get plugin.
void list()
List the various registers.
Gyoto::SmartPointer< Gyoto::SmartPointee > Subcontractor_t(Gyoto::FactoryMessenger *, std::vector< std::string > const &)
A subcontractor builds an object upon order from the Factory.
Definition: GyotoSmartPointer.h:115
Register::Entry * next_
Next entry in the register, or NULL.
Definition: GyotoRegister.h:142
Namespace for the Gyoto library.
Definition: GyotoAstrobj.h:46
std::string name()
Get name.
~Entry()
Destructor.
const std::string plugin_
Plug-in from which this Entry was loaded.
Definition: GyotoRegister.h:144
std::vector< std::string > pluginPath()
Get a copy of the plug-in path.
Gyoto::SmartPointee::Subcontractor_t * subcontractor_
Pointer to the Gyoto::SmartPointee::Subcontractor_t function that produces an object of this kind...
Definition: GyotoRegister.h:140
bool havePlugin(std::string plugname)
Check whether a given plug-in has already been loaded.
void requirePlugin(std::string plugname, int nofail=0)
Load a plugin by name, only if not loaded yet.
Register::Entry * next()
Get next.
Entry in a register (or a full register)
Definition: GyotoRegister.h:132