]> git.sesse.net Git - vlc/blob - src/modules/entry.c
Create primary module from plug-in descriptor and factor code
[vlc] / src / modules / entry.c
1 /*****************************************************************************
2  * entry.c : Callbacks for module entry point
3  *****************************************************************************
4  * Copyright (C) 2007 the VideoLAN team
5  * Copyright © 2007-2008 Rémi Denis-Courmont
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
20  *****************************************************************************/
21
22 #ifdef HAVE_CONFIG_H
23 # include "config.h"
24 #endif
25
26 #include <vlc_common.h>
27 #include <vlc_plugin.h>
28 #include <vlc_memory.h>
29 #include <assert.h>
30 #include <stdarg.h>
31 #include <limits.h>
32
33 #include "modules/modules.h"
34 #include "config/configuration.h"
35 #include "libvlc.h"
36
37 static char *strdup_null (const char *str)
38 {
39     return (str != NULL) ? strdup (str) : NULL;
40 }
41
42 module_t *vlc_module_create (module_t *parent)
43 {
44     module_t *module = malloc (sizeof (*module));
45     if (module == NULL)
46         return NULL;
47
48     /* TODO: replace module/submodules with plugin/modules */
49     if (parent == NULL)
50     {
51         module->next = NULL;
52         module->parent = NULL;
53     }
54     else
55     {
56         module->next = parent->submodule;
57         parent->submodule = module;
58         parent->submodule_count++;
59         module->parent = parent;
60     }
61
62     module->submodule = NULL;
63     module->submodule_count = 0;
64
65     module->psz_shortname = NULL;
66     module->psz_longname = NULL;
67     module->psz_help = NULL;
68     module->pp_shortcuts = NULL;
69     module->i_shortcuts = 0;
70     module->psz_capability = NULL;
71     module->i_score = (parent != NULL) ? parent->i_score : 1;
72     module->b_loaded = false;
73     module->b_unloadable = parent == NULL;
74     module->pf_activate = NULL;
75     module->pf_deactivate = NULL;
76     module->p_config = NULL;
77     module->confsize = 0;
78     module->i_config_items = 0;
79     module->i_bool_items = 0;
80     /*module->handle = garbage */
81     module->psz_filename = NULL;
82     module->domain = NULL;
83     return module;
84 }
85
86 void vlc_module_destroy (module_t *module)
87 {
88     for (module_t *m = module->submodule, *next; m != NULL; m = next)
89     {
90         next = m->next;
91         vlc_module_destroy (m);
92     }
93
94     free (module->domain);
95     free (module->psz_filename);
96     for (unsigned i = 0; i < module->i_shortcuts; i++)
97         free (module->pp_shortcuts[i]);
98     free (module->pp_shortcuts);
99     free (module->psz_capability);
100     free (module->psz_help);
101     free (module->psz_longname);
102     free (module->psz_shortname);
103     free (module);
104 }
105
106 static module_config_t *vlc_config_create (module_t *module, int type)
107 {
108     unsigned confsize = module->confsize;
109     module_config_t *tab = module->p_config;
110
111     if ((confsize & 0xf) == 0)
112     {
113         tab = realloc_or_free (tab, (confsize + 17) * sizeof (*tab));
114         if (tab == NULL)
115             return NULL;
116
117         module->p_config = tab;
118     }
119
120     memset (tab + confsize, 0, sizeof (tab[confsize]));
121     if (IsConfigIntegerType (type))
122     {
123         tab[confsize].max.i = INT_MAX;
124         tab[confsize].min.i = INT_MIN;
125     }
126     tab[confsize].i_type = type;
127
128     if (CONFIG_ITEM(type))
129     {
130         module->i_config_items++;
131         if (type == CONFIG_ITEM_BOOL)
132             module->i_bool_items++;
133     }
134
135     module->confsize++;
136     return tab + confsize;
137 }
138
139
140 int vlc_plugin_set (module_t *module, module_config_t *item, int propid, ...)
141 {
142     va_list ap;
143     int ret = 0;
144
145     va_start (ap, propid);
146     switch (propid)
147     {
148         case VLC_MODULE_CREATE:
149         {
150             module_t **pp = va_arg (ap, module_t **);
151             module_t *submodule = vlc_module_create (module);
152
153             if (unlikely(submodule == NULL))
154             {
155                 ret = -1;
156                 break;
157             }
158
159             *pp = submodule;
160             if (module == NULL)
161                 break;
162             /* Inheritance. Ugly!! */
163             submodule->pp_shortcuts = xmalloc (sizeof (char **));
164             submodule->pp_shortcuts[0] = strdup_null (module->pp_shortcuts[0]);
165             submodule->i_shortcuts = 1; /* object name */
166
167             submodule->psz_shortname = strdup_null (module->psz_shortname);
168             submodule->psz_longname = strdup_null (module->psz_longname);
169             submodule->psz_capability = strdup_null (module->psz_capability);
170             break;
171         }
172
173         case VLC_CONFIG_CREATE:
174         {
175             int type = va_arg (ap, int);
176             module_config_t **pp = va_arg (ap, module_config_t **);
177             *pp = vlc_config_create (module, type);
178             if (*pp == NULL)
179                 ret = -1;
180             break;
181         }
182
183         case VLC_MODULE_SHORTCUT:
184         {
185             unsigned i_shortcuts = va_arg (ap, unsigned);
186             unsigned index = module->i_shortcuts;
187             /* The cache loader accept only a small number of shortcuts */
188             assert(i_shortcuts + index <= MODULE_SHORTCUT_MAX);
189
190             const char *const *tab = va_arg (ap, const char *const *);
191             char **pp = realloc (module->pp_shortcuts,
192                                  sizeof (pp[0]) * (index + i_shortcuts));
193             if (unlikely(pp == NULL))
194             {
195                 ret = -1;
196                 break;
197             }
198             module->pp_shortcuts = pp;
199             module->i_shortcuts = index + i_shortcuts;
200             pp += index;
201             for (unsigned i = 0; i < i_shortcuts; i++)
202                 pp[i] = strdup (tab[i]);
203             break;
204         }
205
206         case VLC_MODULE_CAPABILITY:
207             free (module->psz_capability);
208             module->psz_capability = strdup (va_arg (ap, char *));
209             break;
210
211         case VLC_MODULE_SCORE:
212             module->i_score = va_arg (ap, int);
213             break;
214
215         case VLC_MODULE_CB_OPEN:
216             module->pf_activate = va_arg (ap, void *);
217             break;
218
219         case VLC_MODULE_CB_CLOSE:
220             module->pf_deactivate = va_arg (ap, void *);
221             break;
222
223         case VLC_MODULE_NO_UNLOAD:
224             assert (module->parent == NULL);
225             module->b_unloadable = false;
226             break;
227
228         case VLC_MODULE_NAME:
229         {
230             const char *value = va_arg (ap, const char *);
231
232             assert (module->i_shortcuts == 0);
233             module->pp_shortcuts = malloc( sizeof( char ** ) );
234             module->pp_shortcuts[0] = strdup (value);
235             module->i_shortcuts = 1;
236
237             assert (module->psz_longname == NULL);
238             module->psz_longname = strdup (value);
239             break;
240         }
241
242         case VLC_MODULE_SHORTNAME:
243             assert (module->psz_shortname == NULL || module->parent != NULL);
244             free (module->psz_shortname);
245             module->psz_shortname = strdup (va_arg (ap, char *));
246             break;
247
248         case VLC_MODULE_DESCRIPTION:
249             // TODO: do not set this in VLC_MODULE_NAME
250             free (module->psz_longname);
251             module->psz_longname = strdup (va_arg (ap, char *));
252             break;
253
254         case VLC_MODULE_HELP:
255             assert (module->parent == NULL);
256             assert (module->psz_help == NULL);
257             module->psz_help = strdup (va_arg (ap, char *));
258             break;
259
260         case VLC_MODULE_TEXTDOMAIN:
261             assert (module->parent == NULL);
262             assert (module->domain == NULL);
263             module->domain = strdup (va_arg (ap, char *));
264             break;
265
266         case VLC_CONFIG_NAME:
267         {
268             const char *name = va_arg (ap, const char *);
269
270             assert (name != NULL);
271             item->psz_name = strdup (name);
272             break;
273         }
274
275         case VLC_CONFIG_VALUE:
276         {
277             if (IsConfigIntegerType (item->i_type)
278              || !CONFIG_ITEM(item->i_type))
279             {
280                 item->orig.i =
281                 item->value.i = va_arg (ap, int64_t);
282             }
283             else
284             if (IsConfigFloatType (item->i_type))
285             {
286                 item->orig.f =
287                 item->value.f = va_arg (ap, double);
288             }
289             else
290             if (IsConfigStringType (item->i_type))
291             {
292                 const char *value = va_arg (ap, const char *);
293                 item->value.psz = value ? strdup (value) : NULL;
294                 item->orig.psz = value ? strdup (value) : NULL;
295             }
296             break;
297         }
298
299         case VLC_CONFIG_RANGE:
300         {
301             if (IsConfigIntegerType (item->i_type)
302              || !CONFIG_ITEM(item->i_type))
303             {
304                 item->min.i = va_arg (ap, int64_t);
305                 item->max.i = va_arg (ap, int64_t);
306             }
307             else
308             if (IsConfigFloatType (item->i_type))
309             {
310                 item->min.f = va_arg (ap, double);
311                 item->max.f = va_arg (ap, double);
312             }
313             break;
314         }
315
316         case VLC_CONFIG_ADVANCED:
317             item->b_advanced = true;
318             break;
319
320         case VLC_CONFIG_VOLATILE:
321             item->b_unsaveable = true;
322             break;
323
324         case VLC_CONFIG_PRIVATE:
325             item->b_internal = true;
326             break;
327
328         case VLC_CONFIG_REMOVED:
329             item->b_removed = true;
330             break;
331
332         case VLC_CONFIG_CAPABILITY:
333         {
334             const char *cap = va_arg (ap, const char *);
335             item->psz_type = cap ? strdup (cap) : NULL;
336             break;
337         }
338
339         case VLC_CONFIG_SHORTCUT:
340             item->i_short = va_arg (ap, int);
341             break;
342
343         case VLC_CONFIG_OLDNAME:
344         {
345             const char *oldname = va_arg (ap, const char *);
346             assert (item->psz_oldname == NULL);
347             item->psz_oldname = oldname ? strdup (oldname) : NULL;
348             break;
349         }
350
351         case VLC_CONFIG_SAFE:
352             item->b_safe = true;
353             break;
354
355         case VLC_CONFIG_DESC:
356         {
357             const char *text = va_arg (ap, const char *);
358             const char *longtext = va_arg (ap, const char *);
359
360             item->psz_text = text ? strdup (text) : NULL;
361             item->psz_longtext = longtext ? strdup (longtext) : NULL;
362             break;
363         }
364
365         case VLC_CONFIG_LIST:
366         {
367             size_t len = va_arg (ap, size_t);
368
369             /* Copy values */
370             if (IsConfigIntegerType (item->i_type))
371             {
372                 const int *src = va_arg (ap, const int *);
373                 int *dst = malloc (sizeof (int) * (len + 1));
374
375                 if (dst != NULL)
376                 {
377                     memcpy (dst, src, sizeof (int) * len);
378                     dst[len] = 0;
379                 }
380                 item->pi_list = dst;
381             }
382             else
383             if (IsConfigStringType (item->i_type))
384             {
385                 const char *const *src = va_arg (ap, const char *const *);
386                 char **dst = malloc (sizeof (char *) * (len + 1));
387
388                 if (dst != NULL)
389                 {
390                     for (size_t i = 0; i < len; i++)
391                         dst[i] = src[i] ? strdup (src[i]) : NULL;
392                     dst[len] = NULL;
393                 }
394                 item->ppsz_list = dst;
395             }
396             else
397                 break;
398
399             /* Copy textual descriptions */
400             const char *const *text = va_arg (ap, const char *const *);
401             if (text != NULL)
402             {
403                 char **dtext = malloc (sizeof (char *) * (len + 1));
404                 if( dtext != NULL )
405                 {
406                     for (size_t i = 0; i < len; i++)
407                         dtext[i] = text[i] ? strdup (text[i]) : NULL;
408                     dtext[len] = NULL;
409                 }
410                 item->ppsz_list_text = dtext;
411             }
412             else
413                 item->ppsz_list_text = NULL;
414
415             item->i_list = len;
416             item->pf_update_list = va_arg (ap, vlc_callback_t);
417             break;
418         }
419
420         case VLC_CONFIG_ADD_ACTION:
421         {
422             vlc_callback_t cb = va_arg (ap, vlc_callback_t), *tabcb;
423             const char *name = va_arg (ap, const char *);
424             char **tabtext;
425
426             tabcb = realloc (item->ppf_action,
427                              (item->i_action + 2) * sizeof (cb));
428             if (tabcb == NULL)
429                 break;
430             item->ppf_action = tabcb;
431             tabcb[item->i_action] = cb;
432             tabcb[item->i_action + 1] = NULL;
433
434             tabtext = realloc (item->ppsz_action_text,
435                                (item->i_action + 2) * sizeof (name));
436             if (tabtext == NULL)
437                 break;
438             item->ppsz_action_text = tabtext;
439
440             if (name)
441                 tabtext[item->i_action] = strdup (name);
442             else
443                 tabtext[item->i_action] = NULL;
444             tabtext[item->i_action + 1] = NULL;
445
446             item->i_action++;
447             break;
448         }
449
450         default:
451             fprintf (stderr, "LibVLC: unknown module property %d\n", propid);
452             fprintf (stderr, "LibVLC: too old to use this module?\n");
453             ret = -1;
454             break;
455     }
456
457     va_end (ap);
458     return ret;
459 }