OpenCPN Partial API docs
Loading...
Searching...
No Matches
plugin_paths.cpp
Go to the documentation of this file.
1/**************************************************************************
2 * Copyright (C) 2010 - 2023 by David S. Register *
3 * Copyright (C) 2023 - 2025 Alec Leamas *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, see <https://www.gnu.org/licenses/>. *
17 **************************************************************************/
18
30#include <sstream>
31
32#include <wx/filename.h>
33#include <wx/platinfo.h>
34#include <wx/string.h>
35
36#include "config.h"
37
38#include "model/base_platform.h"
39#include "model/cmdline.h"
40#include "model/ocpn_utils.h"
41#include "model/plugin_paths.h"
42#include "ocpn_plugin.h"
43
44static std::vector<std::string> split(const std::string& s, char delimiter) {
45 std::vector<std::string> tokens;
46 std::string token;
47 std::istringstream tokenStream(s);
48 while (std::getline(tokenStream, token, delimiter)) {
49 tokens.push_back(token);
50 }
51 return tokens;
52}
53
54static std::string expand(const std::string& s) {
55 wxFileName fn(s);
56 fn.Normalize();
57 return fn.GetFullPath().ToStdString();
58}
59
61 static PluginPaths* instance = 0;
62 if (!instance) {
63 instance = new (PluginPaths);
64 }
65 return instance;
66}
67
68void PluginPaths::InitWindowsPaths() {
69 using namespace std;
70
71 if (g_bportable) {
72 m_userLibdir =
73 g_BasePlatform->GetPrivateDataDir().ToStdString() + "\\plugins";
74 m_libdirs.push_back(m_userLibdir);
75 m_user_bindir =
76 g_BasePlatform->GetPrivateDataDir().ToStdString() + "\\plugins";
77 m_bindirs = m_libdirs;
78 m_user_datadir =
79 g_BasePlatform->GetPrivateDataDir().ToStdString() + "\\plugins";
80 m_datadirs.push_back(m_user_datadir);
81 return;
82 }
83
84 const string platform_dir = g_BasePlatform->GetPluginDir().ToStdString();
85 const string winPluginBaseDir =
86 g_BasePlatform->GetWinPluginBaseDir().ToStdString();
87 m_userLibdir = winPluginBaseDir;
88 m_user_bindir = winPluginBaseDir;
89 m_user_datadir = winPluginBaseDir;
90
91 m_libdirs.push_back(m_userLibdir);
92 m_libdirs.push_back(g_BasePlatform->GetPluginDir().ToStdString());
93 m_bindirs = m_libdirs;
94
95 m_datadirs.push_back(platform_dir + "\\plugins");
96 m_datadirs.push_back(winPluginBaseDir);
97}
98
99void PluginPaths::InitFlatpakPaths() {
100 using namespace std;
101
102 const string flathome = m_home + "/.var/app/org.opencpn.OpenCPN";
103 m_userLibdir = flathome + "/lib";
104 m_user_bindir = flathome + "/bin";
105 m_user_datadir = flathome + "/data";
106
107 m_libdirs.push_back(flathome + "/lib");
108 m_libdirs.push_back("/app/extensions/lib/opencpn");
109 m_libdirs.push_back("/app/lib/opencpn");
110
111 m_bindirs.push_back(flathome + "/bin");
112 m_bindirs.push_back("/app/extensions/bin");
113 m_bindirs.push_back("/app/bin");
114
115 m_datadirs.push_back(flathome + "/data/plugins");
116 m_datadirs.push_back("/app/extensions/share/opencpn/plugins");
117 m_datadirs.push_back("/app/share/opencpn/plugins");
118}
119
120void PluginPaths::InitLinuxPaths() {
121 using namespace std;
122
123 if (g_bportable) {
124 m_userLibdir = g_BasePlatform->GetPrivateDataDir().ToStdString() +
125 "/plugins/lib"; // m_home + "/.local/lib";
126 m_libdirs.push_back(m_userLibdir);
127 m_user_bindir = g_BasePlatform->GetPrivateDataDir().ToStdString() +
128 "/plugins/bin"; // m_home + "/.local/bin";
129 m_bindirs = m_libdirs;
130 m_user_datadir = g_BasePlatform->GetPrivateDataDir().ToStdString() +
131 "/plugins/share"; // m_home + "/.local/share";
132 m_datadirs.push_back(m_user_datadir);
133 return;
134 }
135
136 m_userLibdir = m_home + "/.local/lib";
137 m_user_bindir = m_home + "/.local/bin";
138 m_user_datadir = m_home + "/.local/share";
139
140 std::vector<std::string> base_plugin_paths;
141#if defined(__WXGTK__) || defined(__WXQT__)
142 char exe_buf[100] = {0};
143 ssize_t len = readlink("/proc/self/exe", exe_buf, 99);
144 if (len > 0) {
145 exe_buf[len] = '\0';
146 wxFileName fn(exe_buf);
147 std::string path = fn.GetPath().ToStdString();
148 base_plugin_paths.push_back(expand(path + "/../lib/opencpn"));
149 if (g_BasePlatform->GetOSDetail()->osd_arch.find("64") != string::npos) {
150 base_plugin_paths.push_back(expand(path + "/../lib64/opencpn"));
151 } else {
152 base_plugin_paths.push_back(expand(path + "/../lib32/opencpn"));
153 }
154 }
155#endif
156
157 const char* const envdirs = getenv("OPENCPN_PLUGIN_DIRS");
158 string dirlist = envdirs ? envdirs : "~/.local/lib/opencpn";
159 m_libdirs = split(dirlist, ':');
160 for (auto& dir : m_libdirs) {
161 dir = expand(dir);
162 }
163 for (auto& base_plugin_path : base_plugin_paths) {
164 if (envdirs == 0 && dirlist.find(base_plugin_path) == string::npos) {
165 if (ocpn::exists(base_plugin_path)) {
166 m_libdirs.push_back(base_plugin_path);
167 }
168 }
169 }
170 m_bindirs = m_libdirs;
171 for (auto& dir : m_bindirs) {
172 // Fails on Debian multilib paths like /usr/lib/x86_64-linux-gnu.
173 // But we don't use those even on Debian.
174 size_t pos = dir.rfind("/lib/opencpn");
175 if (pos == string::npos) {
176 pos = dir.rfind("/lib64/opencpn");
177 }
178 dir = pos == string::npos ? dir : dir.substr(0, pos) + "/bin";
179 }
180 const char* const xdg_data_dirs = getenv("XDG_DATA_DIRS");
181 dirlist = xdg_data_dirs ? xdg_data_dirs : "~/.local/lib";
182 m_datadirs = split(dirlist, ':');
183 for (auto& dir : m_datadirs) {
184 dir += "/opencpn/plugins";
185 }
186 for (auto& base_plugin_path : base_plugin_paths) {
187 if (xdg_data_dirs == 0 && dirlist.find(base_plugin_path) == string::npos) {
188 m_datadirs.push_back(base_plugin_path + "/plugins");
189 }
190 }
191}
192
193void PluginPaths::InitApplePaths() {
194 using namespace std;
195
196 const string mac_home = m_home + "/Library/Application Support/OpenCPN";
197 m_userLibdir = mac_home + "/Contents/PlugIns";
198 m_user_bindir = m_userLibdir;
199 m_user_datadir = mac_home + "/Contents";
200
201 m_libdirs.push_back(m_userLibdir);
202 wxFileName fn_exe(g_BasePlatform->GetExePath());
203 fn_exe.RemoveLastDir();
204 string exeLibDir =
205 fn_exe.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR).ToStdString() +
206 "PlugIns";
207 m_libdirs.push_back(exeLibDir);
208 // m_libdirs.push_back("/Applications/OpenCPN.app/Contents/Plugins");
209 m_bindirs = m_libdirs;
210
211 m_datadirs.push_back(m_user_datadir);
212 m_datadirs.push_back("/Applications/OpenCPN.app/Contents/PlugIns");
213}
214
215void PluginPaths::InitAndroidPaths() {
216 using namespace std;
217
218 const string platform_dir = g_BasePlatform->GetPluginDir().ToStdString();
219
220 m_userLibdir =
221 platform_dir + "/manPlug"; //("/data/user/0/org.opencpn.opencpn");
222 m_user_bindir =
223 platform_dir + "/manPlug"; //("/data/user/0/org.opencpn.opencpn");
224 m_user_datadir =
226 .ToStdString(); //(
227 //"/storage/emulated/0/android/data/org.opencpn.opencpn/files");
228
229 m_libdirs.push_back(m_userLibdir); // Load managed plugins first...
230 m_libdirs.push_back(expand(platform_dir));
231
232 m_bindirs = m_libdirs;
233}
234
235PluginPaths::PluginPaths() {
236 using namespace std;
237
238 wxString wxHome("unusable-$HOME");
239 wxGetEnv("HOME", &wxHome);
240 m_home = wxHome.ToStdString();
241
242 auto osSystemId = wxPlatformInfo::Get().GetOperatingSystemId();
243 if (osSystemId & wxOS_WINDOWS) {
244 InitWindowsPaths();
245 } else if (g_BasePlatform->isFlatpacked()) {
246 InitFlatpakPaths();
247 } else if (osSystemId & wxOS_UNIX_LINUX) {
248#ifdef __ANDROID__
249 InitAndroidPaths();
250#else
251 InitLinuxPaths();
252#endif
253 } else if (osSystemId & wxOS_MAC) {
254 InitApplePaths();
255 } else {
256 wxString os_name = wxPlatformInfo::Get().GetPortIdName();
257 wxLogMessage("OS_NAME: " + os_name);
258 if (os_name.Contains("wxQT")) {
259 InitAndroidPaths();
260 } else
261 wxLogWarning("PluginPaths: Unknown platform");
262 }
263}
BasePlatform * g_BasePlatform
points to g_platform, handles brain-dead MS linker.
Basic platform specific support utilities without GUI deps.
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.
Accessors for various paths to install plugins and their data.
static PluginPaths * GetInstance()
Return the singleton instance.
Global variables reflecting command line options and arguments.
std::vector< std::string > split(const char *token_string, const std::string &delimiter)
Return vector of items in s separated by delimiter.
bool exists(const std::string &name)
PlugIn Object Definition/API.
Miscellaneous utilities, many of which string related.
Plugin installation and data paths support.