OpenCPN Partial API docs
plugin_paths.cpp
1 #include <sstream>
2 
3 #include <wx/filename.h>
4 #include <wx/platinfo.h>
5 #include <wx/string.h>
6 
7 #include "config.h"
8 
9 #include "model/base_platform.h"
10 #include "model/cmdline.h"
11 #include "model/ocpn_utils.h"
12 #include "model/plugin_paths.h"
13 #include "ocpn_plugin.h"
14 
15 /*
16  * The user-writable paths for libraries, binaries and plugin data,
17  * one path each. And the list of paths used fo loading plugin
18  * plugin libraries, locating helper binaries and storing plugin
19  * data.
20  */
21 
22 static std::vector<std::string> split(const std::string& s, char delimiter) {
23  std::vector<std::string> tokens;
24  std::string token;
25  std::istringstream tokenStream(s);
26  while (std::getline(tokenStream, token, delimiter)) {
27  tokens.push_back(token);
28  }
29  return tokens;
30 }
31 
32 static std::string expand(const std::string& s) {
33  wxFileName fn(s);
34  fn.Normalize();
35  return fn.GetFullPath().ToStdString();
36 }
37 
39  static PluginPaths* instance = 0;
40  if (!instance) {
41  instance = new (PluginPaths);
42  }
43  return instance;
44 }
45 
46 void PluginPaths::initWindowsPaths() {
47  using namespace std;
48 
49  if (g_bportable) {
50  m_userLibdir =
51  g_BasePlatform->GetPrivateDataDir().ToStdString() + "\\plugins";
52  m_libdirs.push_back(m_userLibdir);
53  m_userBindir =
54  g_BasePlatform->GetPrivateDataDir().ToStdString() + "\\plugins";
55  m_bindirs = m_libdirs;
56  m_userDatadir =
57  g_BasePlatform->GetPrivateDataDir().ToStdString() + "\\plugins";
58  m_datadirs.push_back(m_userDatadir);
59  return;
60  }
61 
62  const string platform_dir = g_BasePlatform->GetPluginDir().ToStdString();
63  const string winPluginBaseDir =
64  g_BasePlatform->GetWinPluginBaseDir().ToStdString();
65  m_userLibdir = winPluginBaseDir;
66  m_userBindir = winPluginBaseDir;
67  m_userDatadir = winPluginBaseDir;
68 
69  m_libdirs.push_back(m_userLibdir);
70  m_libdirs.push_back(g_BasePlatform->GetPluginDir().ToStdString());
71  m_bindirs = m_libdirs;
72 
73  m_datadirs.push_back(platform_dir + "\\plugins");
74  m_datadirs.push_back(winPluginBaseDir);
75 }
76 
77 void PluginPaths::initFlatpackPaths() {
78  using namespace std;
79 
80  const string flathome = m_home + "/.var/app/org.opencpn.OpenCPN";
81  m_userLibdir = flathome + "/lib";
82  m_userBindir = flathome + "/bin";
83  m_userDatadir = flathome + "/data";
84 
85  m_libdirs.push_back(flathome + "/lib");
86  m_libdirs.push_back("/app/extensions/lib/opencpn");
87  m_libdirs.push_back("/app/lib/opencpn");
88 
89  m_bindirs.push_back(flathome + "/bin");
90  m_bindirs.push_back("/app/extensions/bin");
91  m_bindirs.push_back("/app/bin");
92 
93  m_datadirs.push_back(flathome + "/data/plugins");
94  m_datadirs.push_back("/app/extensions/share/opencpn/plugins");
95  m_datadirs.push_back("/app/share/opencpn/plugins");
96 }
97 
98 void PluginPaths::initLinuxPaths() {
99  using namespace std;
100 
101  if (g_bportable) {
102  m_userLibdir = g_BasePlatform->GetPrivateDataDir().ToStdString() +
103  "/plugins/lib"; // m_home + "/.local/lib";
104  m_libdirs.push_back(m_userLibdir);
105  m_userBindir = g_BasePlatform->GetPrivateDataDir().ToStdString() +
106  "/plugins/bin"; // m_home + "/.local/bin";
107  m_bindirs = m_libdirs;
108  m_userDatadir = g_BasePlatform->GetPrivateDataDir().ToStdString() +
109  "/plugins/share"; // m_home + "/.local/share";
110  m_datadirs.push_back(m_userDatadir);
111  return;
112  }
113 
114  m_userLibdir = m_home + "/.local/lib";
115  m_userBindir = m_home + "/.local/bin";
116  m_userDatadir = m_home + "/.local/share";
117 
118  std::vector<std::string> base_plugin_paths;
119 #if defined(__WXGTK__) || defined(__WXQT__)
120  char exe_buf[100] = {0};
121  ssize_t len = readlink("/proc/self/exe", exe_buf, 99);
122  if (len > 0){
123  exe_buf[len] = '\0';
124  wxFileName fn(exe_buf);
125  std::string path = fn.GetPath().ToStdString();
126  base_plugin_paths.push_back(expand(path + "/../lib/opencpn"));
127  if(g_BasePlatform->GetOSDetail()->osd_arch.find("64") != string::npos) {
128  base_plugin_paths.push_back(expand(path + "/../lib64/opencpn"));
129  } else {
130  base_plugin_paths.push_back(expand(path + "/../lib32/opencpn"));
131  }
132  }
133 #endif
134 
135  const char* const envdirs = getenv("OPENCPN_PLUGIN_DIRS");
136  string dirlist = envdirs ? envdirs : "~/.local/lib/opencpn";
137  m_libdirs = split(dirlist, ':');
138  for (auto& dir : m_libdirs) {
139  dir = expand(dir);
140  }
141  for (auto &base_plugin_path : base_plugin_paths) {
142  if (envdirs == 0 && dirlist.find(base_plugin_path) == string::npos) {
143  if(ocpn::exists(base_plugin_path)) {
144  m_libdirs.push_back(base_plugin_path);
145  }
146  }
147  }
148  m_bindirs = m_libdirs;
149  for (auto& dir : m_bindirs) {
150  // Fails on Debian multilib paths like /usr/lib/x86_64-linux-gnu.
151  // But we don't use those even on Debian.
152  size_t pos = dir.rfind("/lib/opencpn");
153  if (pos == string::npos) {
154  pos = dir.rfind("/lib64/opencpn");
155  }
156  dir = pos == string::npos ? dir : dir.substr(0, pos) + "/bin";
157  }
158  const char* const xdg_data_dirs = getenv("XDG_DATA_DIRS");
159  dirlist = xdg_data_dirs ? xdg_data_dirs : "~/.local/lib";
160  m_datadirs = split(dirlist, ':');
161  for (auto& dir : m_datadirs) {
162  dir += "/opencpn/plugins";
163  }
164  for (auto &base_plugin_path : base_plugin_paths) {
165  if (xdg_data_dirs == 0 && dirlist.find(base_plugin_path) == string::npos) {
166  m_datadirs.push_back(base_plugin_path + "/plugins");
167  }
168  }
169 }
170 
171 void PluginPaths::initApplePaths() {
172  using namespace std;
173 
174  const string mac_home = m_home + "/Library/Application Support/OpenCPN";
175  m_userLibdir = mac_home + "/Contents/PlugIns";
176  m_userBindir = m_userLibdir;
177  m_userDatadir = mac_home + "/Contents";
178 
179  m_libdirs.push_back(m_userLibdir);
180  wxFileName fn_exe(g_BasePlatform->GetExePath());
181  fn_exe.RemoveLastDir();
182  string exeLibDir =
183  fn_exe.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR).ToStdString() +
184  "PlugIns";
185  m_libdirs.push_back(exeLibDir);
186  // m_libdirs.push_back("/Applications/OpenCPN.app/Contents/Plugins");
187  m_bindirs = m_libdirs;
188 
189  m_datadirs.push_back(m_userDatadir);
190  m_datadirs.push_back("/Applications/OpenCPN.app/Contents/PlugIns");
191 }
192 
193 void PluginPaths::initAndroidPaths() {
194  using namespace std;
195 
196  const string platform_dir = g_BasePlatform->GetPluginDir().ToStdString();
197 
198  m_userLibdir =
199  platform_dir + "/manPlug"; //("/data/user/0/org.opencpn.opencpn");
200  m_userBindir =
201  platform_dir + "/manPlug"; //("/data/user/0/org.opencpn.opencpn");
202  m_userDatadir =
203  g_BasePlatform->GetPrivateDataDir()
204  .ToStdString(); //(
205  //"/storage/emulated/0/android/data/org.opencpn.opencpn/files");
206 
207  m_libdirs.push_back(m_userLibdir); // Load managed plugins first...
208  m_libdirs.push_back(expand(platform_dir));
209 
210  m_bindirs = m_libdirs;
211 }
212 
213 PluginPaths::PluginPaths() {
214  using namespace std;
215 
216  wxString wxHome("unusable-$HOME");
217  wxGetEnv("HOME", &wxHome);
218  m_home = wxHome.ToStdString();
219 
220  auto osSystemId = wxPlatformInfo::Get().GetOperatingSystemId();
221  if (osSystemId & wxOS_WINDOWS) {
222  initWindowsPaths();
223  } else if (g_BasePlatform->isFlatpacked()) {
224  initFlatpackPaths();
225  } else if (osSystemId & wxOS_UNIX_LINUX) {
226 #ifdef __OCPN__ANDROID__
227  initAndroidPaths();
228 #else
229  initLinuxPaths();
230 #endif
231  } else if (osSystemId & wxOS_MAC) {
232  initApplePaths();
233  } else {
234  wxString os_name = wxPlatformInfo::Get().GetPortIdName();
235  wxLogMessage(_T("OS_NAME: ") + os_name);
236  if (os_name.Contains(_T("wxQT"))) {
237  initAndroidPaths();
238  } else
239  wxLogWarning("PluginPaths: Unknown platform");
240  }
241 }
wxString & GetPluginDir()
The original in-tree plugin directory, sometimes not user-writable.
wxString GetWinPluginBaseDir()
Base directory for user writable windows plugins, reflects winPluginDir option, defaults to LOCALAPPD...
wxString & GetPrivateDataDir()
Return dir path for opencpn.log, etc., respecting -c cli option.
static PluginPaths * getInstance()
Return the singleton instance.
Global variables reflecting command line options and arguments.