naev 0.11.5
plugin.c
Go to the documentation of this file.
1/*
2 * See Licensing and Copyright notice in naev.h
3 */
10#include "physfs.h"
11
12#include "naev.h"
15#include "plugin.h"
16
17#define PCRE2_CODE_UNIT_WIDTH 8
18#include <pcre2.h>
19
20#include "log.h"
21#include "array.h"
22#include "nfile.h"
23#include "nxml.h"
24#include "physfs_archiver_blacklist.h"
25
26static plugin_t *plugins;
27
31static int plugin_parse( plugin_t *plg, const char *file, const char *path )
32{
33 xmlNodePtr node, parent;
34 xmlDocPtr doc = xml_parsePhysFS( file );
35 if (doc == NULL)
36 return -1;
37
38 parent = doc->xmlChildrenNode; /* first faction node */
39 if (parent == NULL) {
40 char buf[ PATH_MAX ];
41 nfile_concatPaths( buf, sizeof(buf), plg->mountpoint, file );
42 ERR( _("Malformed '%s' file: does not contain elements"), buf);
43 return -1;
44 }
45
46 xmlr_attr_strd( parent, "name", plg->name );
47 if (plg->name == NULL)
48 WARN(_("Plugin '%s' has no name!"), path);
49
50 node = parent->xmlChildrenNode;
51 do {
52 xml_onlyNodes(node);
53
54 xmlr_strd( node, "author", plg->author );
55 xmlr_strd( node, "version", plg->version );
56 xmlr_strd( node, "description", plg->description );
57 xmlr_strd( node, "compatibility", plg->compatibility );
58 xmlr_int( node, "priority", plg->priority );
59 if (xml_isNode( node, "blacklist" )) {
60 blacklist_append( xml_get(node) );
61 continue;
62 }
63 if (xml_isNode( node, "total_conversion" )) {
64 const char *blk[] = {
65 "^ssys/.*\\.xml",
66 "^spob/.*\\.xml",
67 "^spob_virtual/.*\\.xml",
68 "^factions/.*\\.xml",
69 "^commodities/.*\\.xml",
70 "^ships/.*\\.xml",
71 "^outfits/.*\\.xml",
72 "^missions/.*\\.lua",
73 "^events/.*\\.lua",
74 "^tech/.*\\.xml",
75 "^asteroids/.*\\.xml",
76 "^unidiff/.*\\.xml",
77 "^map_decorator/.*\\.xml",
78 "^intro",
79 NULL
80 };
81 for (int i=0; blk[i]!=NULL; i++)
82 blacklist_append( blk[i] );
83 plg->total_conversion = 1;
84 continue;
85 }
86 WARN(_("Plugin '%s' has unknown metadata node '%s'!"),path,xml_get(node));
87 } while (xml_nextNode(node));
88
89 xmlFreeDoc(doc);
90
91 return 0;
92}
93
97static int plugin_cmp( const void *a, const void *b )
98{
99 const plugin_t *pa = (const plugin_t *) a;
100 const plugin_t *pb = (const plugin_t *) b;
101
102 if (pa->priority < pb->priority)
103 return -1;
104 else if (pa->priority > pb->priority)
105 return 1;
106
107 return strcmp( pa->mountpoint, pb->mountpoint );
108}
109
115int plugin_init (void)
116{
117 char buf[ PATH_MAX ];
118 PHYSFS_Stat stat;
119
120 plugins = array_create( plugin_t );
121
122 PHYSFS_stat( "plugins", &stat );
123 if (stat.filetype == PHYSFS_FILETYPE_DIRECTORY) {
124 int n;
125 char **files = PHYSFS_enumerateFiles( "plugins" );
126 for (char **f = files; *f != NULL; f++) {
127 const char *realdir;
128 plugin_t *plg;
129 nfile_concatPaths( buf, PATH_MAX, PHYSFS_getWriteDir(), "plugins", *f );
130 if (!nfile_fileExists( buf ) && !nfile_dirExists( buf ))
131 continue;
132
133 if (PHYSFS_mount( buf, NULL, 0 )==0) {
134 WARN(_("Failed to mount plugin '%s': %s"), buf,
135 _(PHYSFS_getErrorByCode( PHYSFS_getLastErrorCode()) ));
136 }
137
138 /* Initialize new plugin. */
139 plg = &array_grow( &plugins );
140 memset( plg, 0, sizeof(plugin_t) );
141 plg->mountpoint = strdup( buf );
142 plg->priority = 5;
143
144 PHYSFS_stat( "plugin.xml", &stat );
145 realdir = PHYSFS_getRealDir( "plugin.xml" );
146 if ((stat.filetype == PHYSFS_FILETYPE_REGULAR) &&
147 realdir && strcmp(realdir,buf)==0)
148 plugin_parse( plg, "plugin.xml", *f );
149 else
150 WARN(_("Plugin '%s' does not have a valid '%s'!"), buf, "plugin.xml");
151
152 /* Set some defaults. */
153 if (plg->author == NULL)
154 plg->author = strdup(_("Unknown"));
155 if (plg->version == NULL)
156 plg->version = strdup(_("Unknown"));
157 if (plg->description == NULL)
158 plg->description = strdup(_("Unknown"));
159 }
160 PHYSFS_freeList(files);
161 n = array_size(plugins);
162
163 /* Unmount all. */
164 for (int i=0; i<n; i++)
165 PHYSFS_unmount( plugins[i].mountpoint );
166
167 /* Sort by priority. */
168 qsort( plugins, n, sizeof(plugin_t), plugin_cmp );
169
170 /* Initialize blacklist. */
172
173 /* Remount. */
174 for (int i=n-1; i>=0; i--) /* Reverse order as we prepend. */
175 PHYSFS_mount( plugins[i].mountpoint, NULL, 0 );
176
177 if (n > 0) {
178 DEBUG("Loaded plugins:");
179 for (int i=0; i<n; i++) { /* Reverse order. */
180 DEBUG(" %s", plugin_name( &plugins[i] ) );
181 }
182 }
183 }
184 else {
185 nfile_concatPaths( buf, PATH_MAX, PHYSFS_getWriteDir(), "plugins" );
186 nfile_dirMakeExist( buf );
187 }
188
189 return 0;
190}
191
195void plugin_exit (void)
196{
197 for (int i=0; i<array_size(plugins); i++) {
198 plugin_t *p = &plugins[i];
199 free( p->name );
200 free( p->author );
201 free( p->version );
202 free( p->description );
203 free( p->compatibility );
204 free( p->mountpoint );
205 }
206 array_free(plugins);
207 plugins = NULL;
208
210}
211
218const char *plugin_name( const plugin_t *plg )
219{
220 if (plg->name != NULL)
221 return plg->name;
222 return plg->mountpoint;
223}
224
230int plugin_check (void)
231{
232 int failed = 0;
233 const char *version = naev_version( 0 );
234 for (int i=0; i<array_size(plugins); i++) {
235 int errornumber;
236 PCRE2_SIZE erroroffset;
237 pcre2_code *re;
238 pcre2_match_data *match_data;
239
240 if (plugins[i].compatibility == NULL)
241 continue;
242
243 re = pcre2_compile( (PCRE2_SPTR)plugins[i].compatibility, PCRE2_ZERO_TERMINATED, 0, &errornumber, &erroroffset, NULL );
244 if (re == NULL) {
245 PCRE2_UCHAR buffer[256];
246 pcre2_get_error_message( errornumber, buffer, sizeof(buffer) );
247 WARN(_("Plugin '%s' PCRE2 compilation failed at offset %d: %s"), plugin_name(&plugins[i]), (int)erroroffset, buffer );
248 failed++;
249 continue;
250 }
251
252 match_data = pcre2_match_data_create_from_pattern( re, NULL );
253 int rc = pcre2_match( re, (PCRE2_SPTR)version, strlen(version), 0, 0, match_data, NULL );
254 pcre2_match_data_free( match_data );
255 if (rc < 0) {
256 switch (rc) {
257 case PCRE2_ERROR_NOMATCH:
258 WARN("Plugin '%s' does not support Naev version '%s'.", plugin_name(&plugins[i]), version);
259 failed++;
260 break;
261 default:
262 WARN(_("Matching error %d"), rc );
263 failed++;
264 break;
265 }
266 }
267 else
268 plugins[i].compatible = 1;
269
270 pcre2_code_free( re );
271 }
272
273 return failed;
274}
275
282{
283 return plugins;
284}
Provides macros to work with dynamic arrays.
#define array_free(ptr_array)
Frees memory allocated and sets array to NULL.
Definition array.h:158
static ALWAYS_INLINE int array_size(const void *array)
Returns number of elements in the array.
Definition array.h:168
#define array_grow(ptr_array)
Increases the number of elements by one and returns the last element.
Definition array.h:119
#define array_create(basic_type)
Creates a new dynamic array of ‘basic_type’.
Definition array.h:93
Header file with generic functions and naev-specifics.
const char * naev_version(int long_version)
Returns the version in a human readable string.
#define PATH_MAX
Definition naev.h:50
int nfile_dirMakeExist(const char *path)
Creates a directory if it doesn't exist.
Definition nfile.c:267
int nfile_fileExists(const char *path)
Checks to see if a file exists.
Definition nfile.c:316
int nfile_dirExists(const char *path)
Checks to see if a directory exists.
Definition nfile.c:296
xmlDocPtr xml_parsePhysFS(const char *filename)
Analogous to xmlParseMemory/xmlParseFile.
Definition nxml.c:75
int blacklist_init(void)
Initializes the blacklist system if necessary. If no plugin is blacklisting, it will not do anything.
int blacklist_append(const char *path)
Appends a regex string to be blacklisted.
void blacklist_exit(void)
Exits the blacklist system and cleans up as necessary.
int plugin_init(void)
Initialize and loads all the available plugins.
Definition plugin.c:115
int plugin_check(void)
Checks to see if the plugins are self-declared compatible with Naev.
Definition plugin.c:230
const char * plugin_name(const plugin_t *plg)
Tries to tget the name of a plugin.
Definition plugin.c:218
static int plugin_parse(plugin_t *plg, const char *file, const char *path)
Parses a plugin description file.
Definition plugin.c:31
void plugin_exit(void)
Exits the plugin stuff.
Definition plugin.c:195
static int plugin_cmp(const void *a, const void *b)
For qsort on plugins.
Definition plugin.c:97
const plugin_t * plugin_list(void)
Returns the list of all the plugins.
Definition plugin.c:281
int priority
Definition plugin.h:13
char * mountpoint
Definition plugin.h:12
char * compatibility
Definition plugin.h:11
int compatible
Definition plugin.h:14
char * author
Definition plugin.h:8
char * version
Definition plugin.h:9
int total_conversion
Definition plugin.h:15
char * name
Definition plugin.h:7
char * description
Definition plugin.h:10