Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
dependency.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Author:
4 * Ted Gould <ted@gould.cx>
5 *
6 * Copyright (C) 2006 Johan Engelen, johan@shouraizou.nl
7 * Copyright (C) 2004 Author
8 *
9 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
10 */
11
12#include "dependency.h"
13
14#include <glibmm/i18n.h>
15#include <glibmm/fileutils.h>
16#include <glibmm/miscutils.h>
17
18#include "db.h"
19#include "extension.h"
20#include "io/resource.h"
21#include "xml/node.h"
22
23namespace Inkscape {
24namespace Extension {
25
26// These strings are for XML attribute comparisons and should not be translated;
27// make sure to keep in sync with enum defined in dependency.h
28gchar const * Dependency::_type_str[] = {
29 "executable",
30 "file",
31 "extension",
32};
33
34// These strings are for XML attribute comparisons and should not be translated
35// make sure to keep in sync with enum defined in dependency.h
36gchar const * Dependency::_location_str[] = {
37 "path",
38 "extensions",
39 "inx",
40 "absolute",
41};
42
54Dependency::Dependency (Inkscape::XML::Node * in_repr, const Extension *extension, type_t default_type)
55 : _repr(in_repr)
56 , _extension(extension)
57 , _type(default_type)
58{
60
61 if (const gchar * location = _repr->attribute("location")) {
62 for (int i = 0; i < LOCATION_CNT && location != nullptr; i++) {
63 if (!strcmp(location, _location_str[i])) {
65 break;
66 }
67 }
68 } else if (const gchar * location = _repr->attribute("reldir")) { // backwards-compatibility
69 for (int i = 0; i < LOCATION_CNT && location != nullptr; i++) {
70 if (!strcmp(location, _location_str[i])) {
72 break;
73 }
74 }
75 }
76
77 const gchar * type = _repr->attribute("type");
78 for (int i = 0; i < TYPE_CNT && type != nullptr; i++) {
79 if (!strcmp(type, _type_str[i])) {
80 _type = (type_t)i;
81 break;
82 }
83 }
84
86
87 _description = _repr->attribute("description");
88 if (_description == nullptr)
89 _description = _repr->attribute("_description");
90
91 return;
92}
93
103
135{
136 if (_string == nullptr) {
137 return false;
138 }
139
141
142 switch (_type) {
143 case TYPE_EXTENSION: {
144 Extension * myext = db.get(_string);
145 if (myext == nullptr) return false;
146 if (myext->deactivated()) return false;
147 break;
148 }
149 case TYPE_EXECUTABLE:
150 case TYPE_FILE: {
151 Glib::FileTest filetest = Glib::FileTest::EXISTS;
152
153 std::string location(_string);
154
155 // get potential file extension for later usage
156 std::string extension;
157 size_t index = location.find_last_of(".");
158 if (index != std::string::npos) {
159 extension = location.substr(index);
160 }
161
162 // check interpreted scripts as "file" for backwards-compatibility, even if "executable" was requested
163 static const std::vector<std::string> interpreted = {".py", ".pl", ".rb"};
164 if (!extension.empty() &&
165 std::find(interpreted.begin(), interpreted.end(), extension) != interpreted.end())
166 {
168 }
169
170#ifndef _WIN32
171 // There's no executable bit on Windows, so this is unreliable
172 // glib would search for "executable types" instead, which are only {".exe", ".cmd", ".bat", ".com"},
173 // and would therefore miss files without extension and other script files (like .py files)
174 if (_type == TYPE_EXECUTABLE) {
175 filetest = Glib::FileTest::IS_EXECUTABLE;
176 }
177#endif
178
179 switch (_location) {
180 // backwards-compatibility: location="extensions" will be deprecated as of Inkscape 1.1,
181 // use location="inx" instead
182 case LOCATION_EXTENSIONS: {
183 // get_filename will warn if the resource isn't found, while returning an empty string.
184 std::string temploc =
186 if (!temploc.empty()) {
187 location = temploc;
188 _absolute_location = temploc;
189 break;
190 }
191 /* Look for deprecated locations next */
192 auto deprloc = g_build_filename("inkex", "deprecated-simple", location.c_str(), nullptr);
193 std::string tempdepr =
195 g_free(deprloc);
196 if (!tempdepr.empty()) {
197 location = tempdepr;
198 _absolute_location = tempdepr;
199 break;
200 }
201 // PASS THROUGH!!! - also check inx location for backwards-compatibility,
202 // notably to make extension manager work
203 // (installs into subfolders of "extensions" directory)
204 }
205 case LOCATION_INX: {
206 std::string base_directory = _extension->get_base_directory();
207 if (base_directory.empty()) {
208 g_warning("Dependency '%s' requests location relative to .inx file, "
209 "which is unknown for extension '%s'", _string, _extension->get_id());
210 }
211 std::string absolute_location = Glib::build_filename(base_directory, location);
212 if (!Glib::file_test(absolute_location, filetest)) {
213 return false;
214 }
215 _absolute_location = absolute_location;
216 break;
217 }
218 case LOCATION_ABSOLUTE: {
219 // TODO: should we check if the directory actually is absolute and/or sanitize the filename somehow?
220 if (!Glib::file_test(location, filetest)) {
221 return false;
222 }
223 _absolute_location = location;
224 break;
225 }
226 /* The default case is to look in the path */
227 case LOCATION_PATH:
228 default: {
229 // TODO: we can likely use g_find_program_in_path (or its glibmm equivalent) for executable types
230
231 gchar * path = g_strdup(g_getenv("PATH"));
232
233 if (path == nullptr) {
234 /* There is no `PATH' in the environment.
235 The default search path is the current directory */
236 path = g_strdup(G_SEARCHPATH_SEPARATOR_S);
237 }
238
239 gchar * orig_path = path;
240
241 for (; path != nullptr;) {
242 gchar * local_path; // to have the path after detection of the separator
243 std::string final_name;
244
245 local_path = path;
246 path = g_utf8_strchr(path, -1, G_SEARCHPATH_SEPARATOR);
247 /* Not sure whether this is UTF8 happy, but it would seem
248 like it considering that I'm searching (and finding)
249 the ':' character */
250 if (path != nullptr) {
251 path[0] = '\0';
252 path++;
253 }
254
255 if (*local_path == '\0') {
256 final_name = _string;
257 } else {
258 final_name = Glib::build_filename(local_path, _string);
259 }
260
261 if (Glib::file_test(final_name, filetest)) {
262 g_free(orig_path);
263 _absolute_location = final_name;
264 return true;
265 }
266
267#ifdef _WIN32
268 // Unfortunately file extensions tend to be different on Windows and we can't know
269 // which one it is, so try all extensions glib assumes to be executable.
270 // As we can only guess here, return the version without extension if either one is found,
271 // so that we don't accidentally override (or conflict with) some g_spawn_* magic.
272 if (_type == TYPE_EXECUTABLE) {
273 static const std::vector<std::string> extensions = {".exe", ".cmd", ".bat", ".com"};
274 if (extension.empty() ||
275 std::find(extensions.begin(), extensions.end(), extension) == extensions.end())
276 {
277 for (auto extension : extensions) {
278 if (Glib::file_test(final_name + extension, filetest)) {
279 g_free(orig_path);
280 _absolute_location = final_name;
281 return true;
282 }
283 }
284 }
285 }
286#endif
287 }
288
289 g_free(orig_path);
290 return false; /* Reverse logic in this one */
291 }
292 } /* switch _location */
293 break;
294 } /* TYPE_FILE, TYPE_EXECUTABLE */
295 default:
296 return false;
297 } /* switch _type */
298
299 return true;
300}
301
310{
311 return _string;
312}
313
323{
324 if (_type == TYPE_EXTENSION) {
325 g_warning("Requested absolute path of dependency '%s' which is of 'extension' type.", _string);
326 return "";
327 }
329 g_warning("Requested absolute path of dependency '%s' which is unchecked.", _string);
330 return "";
331 }
332
333 return _absolute_location;
334}
335
340{
341 Glib::ustring str = Glib::ustring::compose("%1:\n\t%2: %3\n\t%4: %5\n\t%6: %7",
342 _("Dependency"),
343 _("type"), _(_type_str[_type]),
344 _("location"), _(_location_str[_location]),
345 _("string"), _string);
346
347 if (_description) {
348 str += Glib::ustring::compose("\n\t%1: %2\n", _(" description: "), _(_description));
349 }
350
351 return str;
352}
353
354} } /* namespace Inkscape, Extension */
355
356/*
357 Local Variables:
358 mode:c++
359 c-file-style:"stroustrup"
360 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
361 indent-tabs-mode:nil
362 fill-column:99
363 End:
364*/
365// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
Extension * get(const gchar *key) const
This function looks up a Inkscape::Extension::Extension by using its unique id. It then returns a ref...
Definition db.cpp:101
bool check()
Check if the dependency passes.
Inkscape::XML::Node * _repr
The XML representation of the dependency.
Definition dependency.h:53
Dependency(Inkscape::XML::Node *in_repr, const Extension *extension, type_t type=TYPE_FILE)
Create a dependency using an XML definition.
virtual ~Dependency()
This dependency is not longer needed.
const gchar * _description
The description of the dependency for the users.
Definition dependency.h:57
const Extension * _extension
Reference to the extension requesting this dependency.
Definition dependency.h:74
const gchar * _string
The string that is in the XML tags pulled out.
Definition dependency.h:55
static constexpr const char * UNCHECKED
Definition dependency.h:50
static gchar const * _type_str[TYPE_CNT]
Strings to represent the different enum values in type_t in the XML.
Definition dependency.h:68
const gchar * get_name()
Accessor to the name attribute.
std::string get_path()
Path of this dependency.
std::string _absolute_location
The absolute path to the dependency file determined while checking this dependency.
Definition dependency.h:59
location_t _location
The location to look for this particular dependency.
Definition dependency.h:64
type_t _type
Storing the type of this particular dependency.
Definition dependency.h:62
Glib::ustring info_string()
Print out a dependency to a string.
static gchar const * _location_str[LOCATION_CNT]
Strings to represent the different enum values in location_t in the XML.
Definition dependency.h:71
location_t
All of the possible locations to look for the dependency.
Definition dependency.h:39
@ LOCATION_CNT
Number of locations to look.
Definition dependency.h:46
@ LOCATION_EXTENSIONS
Look in the extensions directory (note: this can be in both, user and system locations!...
Definition dependency.h:42
@ LOCATION_ABSOLUTE
This dependency is already defined in absolute terms.
Definition dependency.h:45
@ LOCATION_INX
Look relative to the inx file's location.
Definition dependency.h:44
@ LOCATION_PATH
Look in the PATH for this dependency - historically this is the default (it's a bit odd for interpret...
Definition dependency.h:40
type_t
All the possible types of dependencies.
Definition dependency.h:31
@ TYPE_EXTENSION
Make sure a specific extension is loaded and functional.
Definition dependency.h:34
@ TYPE_FILE
Look to make sure a file exists.
Definition dependency.h:33
@ TYPE_EXECUTABLE
Look for an executable.
Definition dependency.h:32
The object that is the basis for the Extension system.
Definition extension.h:133
char const * get_id() const
Get the ID of this extension - not a copy don't delete!
auto const & get_base_directory() const
Definition extension.h:192
Interface for refcounted XML nodes.
Definition node.h:80
virtual Node * firstChild()=0
Get the first child of this node.
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
virtual char const * content() const =0
Get the content of a text or comment node.
Inkscape::Extension::Extension: Frontend to certain, possibly pluggable, actions.
DB db
This is the actual database object.
Definition db.cpp:32
static R & anchor(R &r)
Increments the reference count of a anchored object.
Definition gc-anchored.h:92
static R & release(R &r)
Decrements the reference count of a anchored object.
std::string get_filename(Type type, char const *filename, bool localized, bool silent)
Definition resource.cpp:170
Helper class to stream background task notifications as a series of messages.
Inkscape::IO::Resource - simple resource API.
int index
Interface for XML nodes.