1 /*
2 * Author:
3 * Ted Gould <ted@gould.cx>
4 *
5 * Copyright (C) 2006 Johan Engelen, johan@shouraizou.nl
6 * Copyright (C) 2004 Author
7 *
8 * Released under GNU GPL, read the file 'COPYING' for more information
9 */
11 #ifdef HAVE_CONFIG_H
12 #include "config.h"
13 #endif
15 #include <glibmm/i18n.h>
16 #include "config.h"
17 #include "path-prefix.h"
18 #include "dependency.h"
19 #include "db.h"
21 namespace Inkscape {
22 namespace Extension {
24 // These strings are for XML attribute comparisons and should not be translated
25 gchar const * Dependency::_type_str[] = {
26 "executable",
27 "file",
28 "extension",
29 "plugin",
30 };
32 // These strings are for XML attribute comparisons and should not be translated
33 gchar const * Dependency::_location_str[] = {
34 "path",
35 "extensions",
36 "absolute",
37 };
39 /**
40 \brief Create a dependency using an XML definition
41 \param in_repr XML definition of the dependency
43 This function mostly looks for the 'location' and 'type' attributes
44 and turns them into the enums of the same name. This makes things
45 a little bit easier to use later. Also, a pointer to the core
46 content is pulled out -- also to make things easier.
47 */
48 Dependency::Dependency (Inkscape::XML::Node * in_repr)
49 {
50 _type = TYPE_FILE;
51 _location = LOCATION_PATH;
52 _repr = in_repr;
53 _string = NULL;
54 _description = NULL;
56 Inkscape::GC::anchor(_repr);
58 const gchar * location = _repr->attribute("location");
59 for (int i = 0; i < LOCATION_CNT && location != NULL; i++) {
60 if (!strcmp(location, _location_str[i])) {
61 _location = (location_t)i;
62 break;
63 }
64 }
66 const gchar * type = _repr->attribute("type");
67 for (int i = 0; i < TYPE_CNT && type != NULL; i++) {
68 if (!strcmp(type, _type_str[i])) {
69 _type = (type_t)i;
70 break;
71 }
72 }
74 _string = sp_repr_children(_repr)->content();
76 _description = _repr->attribute("description");
77 if (_description == NULL)
78 _description = _repr->attribute("_description");
80 return;
81 }
83 /**
84 \brief This depenency is not longer needed
86 Unreference the XML structure.
87 */
88 Dependency::~Dependency (void)
89 {
90 Inkscape::GC::release(_repr);
91 }
93 /**
94 \brief Check if the dependency passes.
95 \return Whether or not the dependency passes.
97 This function depends largely on all of the enums. The first level
98 that is evaluted is the \c _type.
100 If the type is \c TYPE_EXTENSION then the id for the extension is
101 looked up in the database. If the extension is found, and it is
102 not deactivated, the dependency passes.
104 If the type is \c TYPE_PLUGIN then the path for the plugin is found
105 using the Glib::Module routines. When the path is found, then there
106 is a check to see if the file exists using the \c file_test function.
108 If the type is \c TYPE_EXECUTABLE or \c TYPE_FILE things are getting
109 even more interesting because now the \c _location variable is also
110 taken into account. First, the difference between the two is that
111 the file test for \c TYPE_EXECUTABLE also tests to make sure the
112 file is executable, besides checking that it exists.
114 If the \c _location is \c LOCATION_EXTENSIONS then the \c INKSCAPE_EXTENSIONDIR
115 is put on the front of the string with \c build_filename. Then the
116 appopriate filetest is run.
118 If the \c _location is \c LOCATION_ABSOLUTE then the file test is
119 run directly on the string.
121 If the \c _location is \c LOCATION_PATH or not specified then the
122 path is used to find the file. Each entry in the path is stepped
123 through, attached to the string, and then tested. If the file is
124 found then a TRUE is returned. If we get all the way through the
125 path then a FALSE is returned, the command could not be found.
126 */
127 bool
128 Dependency::check (void) const
129 {
130 // std::cout << "Checking: " << *this << std::endl;
132 if (_string == NULL) return FALSE;
134 switch (_type) {
135 case TYPE_EXTENSION: {
136 Extension * myext = db.get(_string);
137 if (myext == NULL) return FALSE;
138 if (myext->deactivated()) return FALSE;
139 break;
140 }
141 case TYPE_PLUGIN: {
142 if (!Glib::Module::get_supported()) {
143 return FALSE;
144 }
146 std::string path = Glib::Module::build_path(INKSCAPE_PLUGINDIR, _string);
147 if (!Glib::file_test(path, Glib::FILE_TEST_EXISTS))
148 return FALSE;
149 break;
150 }
151 case TYPE_EXECUTABLE:
152 case TYPE_FILE: {
153 Glib::FileTest filetest = Glib::FILE_TEST_EXISTS;
154 if (_type == TYPE_EXECUTABLE) {
155 filetest |= Glib::FILE_TEST_IS_EXECUTABLE;
156 }
158 std::string location(_string);
159 switch (_location) {
160 case LOCATION_EXTENSIONS: {
161 for (unsigned int i=0; i<Inkscape::Extension::Extension::search_path.size(); i++) {
162 std::string temploc = Glib::build_filename(Inkscape::Extension::Extension::search_path[i], location);
163 if (Glib::file_test(temploc, filetest)) {
164 location = temploc;
165 break;
166 }
167 }
168 } /* PASS THROUGH!!! */
169 case LOCATION_ABSOLUTE: {
170 if (!Glib::file_test(location, filetest)) {
171 // std::cout << "Failing on location: " << location << std::endl;
172 return FALSE;
173 }
174 break;
175 }
176 /* The default case is to look in the path */
177 case LOCATION_PATH:
178 default: {
179 gchar * path = g_strdup(g_getenv("PATH"));
181 if (path == NULL) {
182 /* There is no `PATH' in the environment.
183 The default search path is the current directory */
184 path = g_strdup(G_SEARCHPATH_SEPARATOR_S);
185 }
187 gchar * orig_path = path;
189 for (; path != NULL;) {
190 gchar * local_path;
191 gchar * final_name;
193 local_path = path;
194 path = g_utf8_strchr(path, -1, G_SEARCHPATH_SEPARATOR);
195 /* Not sure whether this is UTF8 happy, but it would seem
196 like it considering that I'm searching (and finding)
197 the ':' character */
198 if (path != local_path && path != NULL) {
199 path[0] = '\0';
200 path++;
201 } else {
202 path = NULL;
203 }
205 if (local_path == '\0') {
206 final_name = g_strdup(_string);
207 } else {
208 final_name = g_build_filename(local_path, _string, NULL);
209 }
211 if (Glib::file_test(final_name, filetest)) {
212 g_free(final_name);
213 g_free(orig_path);
214 return TRUE;
215 }
217 // give it a 2nd try with ".exe" added
218 gchar * final_name_exe = g_strdup_printf("%s.exe", final_name);
219 if (Glib::file_test(final_name_exe, filetest)) {
220 g_free(final_name);
221 g_free(final_name_exe);
222 g_free(orig_path);
223 return TRUE;
224 }
225 g_free(final_name_exe);
227 // and a 3rd try with ".cmd" added (mainly for UniConvertor)
228 gchar * final_name_cmd = g_strdup_printf("%s.cmd", final_name);
229 if (Glib::file_test(final_name_cmd, filetest)) {
230 g_free(final_name);
231 g_free(final_name_cmd);
232 g_free(orig_path);
233 return TRUE;
234 }
235 g_free(final_name_cmd);
237 // give up
238 g_free(final_name);
239 }
241 g_free(orig_path);
242 return FALSE; /* Reverse logic in this one */
243 break;
244 }
245 } /* switch _location */
246 break;
247 } /* TYPE_FILE, TYPE_EXECUTABLE */
248 default:
249 return FALSE;
250 } /* switch _type */
252 return TRUE;
253 }
255 /**
256 \brief Print out a dependency to a string.
257 */
258 std::ostream &
259 operator<< (std::ostream &out_file, const Dependency & in_dep)
260 {
261 out_file << _("Dependency:") << '\n';
262 out_file << _(" type: ") << _(in_dep._type_str[in_dep._type]) << '\n';
263 out_file << _(" location: ") << _(in_dep._location_str[in_dep._location]) << '\n';
264 out_file << _(" string: ") << in_dep._string << '\n';
266 if (in_dep._description != NULL) {
267 out_file << _(" description: ") << _(in_dep._description) << '\n';
268 }
270 out_file << std::flush;
272 return out_file;
273 }
275 } } /* namespace Inkscape, Extension */
277 /*
278 Local Variables:
279 mode:c++
280 c-file-style:"stroustrup"
281 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
282 indent-tabs-mode:nil
283 fill-column:99
284 End:
285 */
286 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :