entry.c 13.1 KB
Newer Older
1
2
3
/*****************************************************************************
 * entry.c : Callbacks for module entry point
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
4
 * Copyright (C) 2007 VLC authors and VideoLAN
5
 * Copyright © 2007-2008 Rémi Denis-Courmont
6
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
7
8
9
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
10
11
12
13
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
14
15
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
16
 *
Jean-Baptiste Kempf's avatar
LGPL    
Jean-Baptiste Kempf committed
17
18
19
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
20
21
 *****************************************************************************/

22
23
24
25
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

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
38
39
40
41
static char *strdup_null (const char *str)
{
    return (str != NULL) ? strdup (str) : NULL;
}

42
module_t *vlc_module_create (module_t *parent)
43
{
44
    module_t *module = malloc (sizeof (*module));
45
46
47
    if (module == NULL)
        return NULL;

48
49
50
51
52
53
54
55
56
57
58
59
60
61
    /* TODO: replace module/submodules with plugin/modules */
    if (parent == NULL)
    {
        module->next = NULL;
        module->parent = NULL;
    }
    else
    {
        module->next = parent->submodule;
        parent->submodule = module;
        parent->submodule_count++;
        module->parent = parent;
    }

62
63
64
65
    module->submodule = NULL;
    module->submodule_count = 0;

    module->psz_shortname = NULL;
66
    module->psz_longname = NULL;
67
    module->psz_help = NULL;
68
69
    module->pp_shortcuts = NULL;
    module->i_shortcuts = 0;
70
    module->psz_capability = NULL;
71
72
73
    module->i_score = (parent != NULL) ? parent->i_score : 1;
    module->b_loaded = false;
    module->b_unloadable = parent == NULL;
74
75
76
77
78
79
80
81
    module->pf_activate = NULL;
    module->pf_deactivate = NULL;
    module->p_config = NULL;
    module->confsize = 0;
    module->i_config_items = 0;
    module->i_bool_items = 0;
    /*module->handle = garbage */
    module->psz_filename = NULL;
82
    module->domain = NULL;
83
84
85
    return module;
}

86
87
88
89
/**
 * Destroys a plug-in.
 * @warning If the plug-in is loaded in memory, the handle will be leaked.
 */
90
void vlc_module_destroy (module_t *module)
91
{
92
93
    assert (!module->b_loaded || !module->b_unloadable);

94
95
96
97
98
99
    for (module_t *m = module->submodule, *next; m != NULL; m = next)
    {
        next = m->next;
        vlc_module_destroy (m);
    }

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
100
101
    config_Free (module->p_config, module->confsize);

102
103
    free (module->domain);
    free (module->psz_filename);
104
105
    for (unsigned i = 0; i < module->i_shortcuts; i++)
        free (module->pp_shortcuts[i]);
106
    free (module->pp_shortcuts);
107
108
109
110
    free (module->psz_capability);
    free (module->psz_help);
    free (module->psz_longname);
    free (module->psz_shortname);
111
112
113
    free (module);
}

114
static module_config_t *vlc_config_create (module_t *module, int type)
115
116
117
118
119
120
{
    unsigned confsize = module->confsize;
    module_config_t *tab = module->p_config;

    if ((confsize & 0xf) == 0)
    {
121
        tab = realloc_or_free (tab, (confsize + 17) * sizeof (*tab));
122
123
124
125
126
127
128
        if (tab == NULL)
            return NULL;

        module->p_config = tab;
    }

    memset (tab + confsize, 0, sizeof (tab[confsize]));
129
130
131
132
133
    if (IsConfigIntegerType (type))
    {
        tab[confsize].max.i = INT_MAX;
        tab[confsize].min.i = INT_MIN;
    }
134
    tab[confsize].i_type = type;
135

136
    if (CONFIG_ITEM(type))
137
138
139
140
141
142
143
144
145
146
147
    {
        module->i_config_items++;
        if (type == CONFIG_ITEM_BOOL)
            module->i_bool_items++;
    }

    module->confsize++;
    return tab + confsize;
}


148
149
150
151
/**
 * Callback for the plugin descriptor functions.
 */
static int vlc_plugin_setter (void *plugin, void *tgt, int propid, ...)
152
{
153
154
155
    module_t **pprimary = plugin;
    module_t *module = tgt;
    module_config_t *item = tgt;
156
157
    va_list ap;
    int ret = 0;
158

159
    va_start (ap, propid);
160
161
    switch (propid)
    {
162
        case VLC_MODULE_CREATE:
163
        {
164
            module = *pprimary;
165
            module_t *submodule = vlc_module_create (module);
166
167
            if (unlikely(submodule == NULL))
            {
168
                ret = -1;
169
170
171
                break;
            }

172
173
174
175
            *(va_arg (ap, module_t **)) = submodule;
            if (*pprimary == NULL)
            {
                *pprimary = submodule;
176
                break;
177
            }
178
            /* Inheritance. Ugly!! */
179
            submodule->pp_shortcuts = xmalloc (sizeof ( *submodule->pp_shortcuts ));
180
181
182
183
184
185
            submodule->pp_shortcuts[0] = strdup_null (module->pp_shortcuts[0]);
            submodule->i_shortcuts = 1; /* object name */

            submodule->psz_shortname = strdup_null (module->psz_shortname);
            submodule->psz_longname = strdup_null (module->psz_longname);
            submodule->psz_capability = strdup_null (module->psz_capability);
186
187
188
189
190
191
192
            break;
        }

        case VLC_CONFIG_CREATE:
        {
            int type = va_arg (ap, int);
            module_config_t **pp = va_arg (ap, module_config_t **);
193
194
195
196

            item = vlc_config_create (*pprimary, type);
            if (unlikely(item == NULL))
            {
197
                ret = -1;
198
199
200
                break;
            }
            *pp = item;
201
202
203
            break;
        }

204
205
        case VLC_MODULE_SHORTCUT:
        {
206
207
            unsigned i_shortcuts = va_arg (ap, unsigned);
            unsigned index = module->i_shortcuts;
208
209
210
            /* The cache loader accept only a small number of shortcuts */
            assert(i_shortcuts + index <= MODULE_SHORTCUT_MAX);

211
            const char *const *tab = va_arg (ap, const char *const *);
ivoire's avatar
ivoire committed
212
213
            char **pp = realloc (module->pp_shortcuts,
                                 sizeof (pp[0]) * (index + i_shortcuts));
214
            if (unlikely(pp == NULL))
215
            {
216
217
                ret = -1;
                break;
218
            }
219
220
            module->pp_shortcuts = pp;
            module->i_shortcuts = index + i_shortcuts;
221
222
223
            pp += index;
            for (unsigned i = 0; i < i_shortcuts; i++)
                pp[i] = strdup (tab[i]);
224
225
226
227
            break;
        }

        case VLC_MODULE_CAPABILITY:
228
229
            free (module->psz_capability);
            module->psz_capability = strdup (va_arg (ap, char *));
230
231
232
            break;

        case VLC_MODULE_SCORE:
233
            module->i_score = va_arg (ap, int);
234
235
236
            break;

        case VLC_MODULE_CB_OPEN:
237
            module->pf_activate = va_arg (ap, void *);
238
239
240
            break;

        case VLC_MODULE_CB_CLOSE:
241
            module->pf_deactivate = va_arg (ap, void *);
242
243
            break;

244
        case VLC_MODULE_NO_UNLOAD:
245
            assert (module->parent == NULL);
246
            module->b_unloadable = false;
247
248
            break;

249
        case VLC_MODULE_NAME:
250
251
        {
            const char *value = va_arg (ap, const char *);
252

253
            assert (module->i_shortcuts == 0);
254
            module->pp_shortcuts = malloc( sizeof( *module->pp_shortcuts ) );
255
            module->pp_shortcuts[0] = strdup (value);
256
257
            module->i_shortcuts = 1;

258
259
            assert (module->psz_longname == NULL);
            module->psz_longname = strdup (value);
260
            break;
261
        }
262

263
        case VLC_MODULE_SHORTNAME:
264
265
266
            assert (module->psz_shortname == NULL || module->parent != NULL);
            free (module->psz_shortname);
            module->psz_shortname = strdup (va_arg (ap, char *));
267
268
269
            break;

        case VLC_MODULE_DESCRIPTION:
270
271
272
            // TODO: do not set this in VLC_MODULE_NAME
            free (module->psz_longname);
            module->psz_longname = strdup (va_arg (ap, char *));
273
            break;
274
275

        case VLC_MODULE_HELP:
276
277
            assert (module->parent == NULL);
            assert (module->psz_help == NULL);
278
            module->psz_help = strdup (va_arg (ap, char *));
279
            break;
280

281
        case VLC_MODULE_TEXTDOMAIN:
282
283
284
            assert (module->parent == NULL);
            assert (module->domain == NULL);
            module->domain = strdup (va_arg (ap, char *));
285
286
            break;

287
288
289
290
291
292
293
294
295
296
        case VLC_CONFIG_NAME:
        {
            const char *name = va_arg (ap, const char *);

            assert (name != NULL);
            item->psz_name = strdup (name);
            break;
        }

        case VLC_CONFIG_VALUE:
297
        {
298
299
            if (IsConfigIntegerType (item->i_type)
             || !CONFIG_ITEM(item->i_type))
300
            {
301
                item->orig.i =
302
                item->value.i = va_arg (ap, int64_t);
303
304
305
306
            }
            else
            if (IsConfigFloatType (item->i_type))
            {
307
                item->orig.f =
308
309
310
311
312
313
314
                item->value.f = va_arg (ap, double);
            }
            else
            if (IsConfigStringType (item->i_type))
            {
                const char *value = va_arg (ap, const char *);
                item->value.psz = value ? strdup (value) : NULL;
315
                item->orig.psz = value ? strdup (value) : NULL;
316
317
318
319
            }
            break;
        }

320
        case VLC_CONFIG_RANGE:
321
322
323
324
325
326
        {
            if (IsConfigFloatType (item->i_type))
            {
                item->min.f = va_arg (ap, double);
                item->max.f = va_arg (ap, double);
            }
327
328
329
330
331
            else
            {
                item->min.i = va_arg (ap, int64_t);
                item->max.i = va_arg (ap, int64_t);
            }
332
333
334
            break;
        }

335
        case VLC_CONFIG_ADVANCED:
336
            item->b_advanced = true;
337
338
            break;

339
        case VLC_CONFIG_VOLATILE:
340
            item->b_unsaveable = true;
341
342
            break;

343
        case VLC_CONFIG_PRIVATE:
344
            item->b_internal = true;
345
            break;
346
347

        case VLC_CONFIG_REMOVED:
348
            item->b_removed = true;
349
350
351
352
353
354
355
356
            break;

        case VLC_CONFIG_CAPABILITY:
        {
            const char *cap = va_arg (ap, const char *);
            item->psz_type = cap ? strdup (cap) : NULL;
            break;
        }
357
358
359
360
361

        case VLC_CONFIG_SHORTCUT:
            item->i_short = va_arg (ap, int);
            break;

362
363
364
365
366
367
368
369
370
        case VLC_CONFIG_SAFE:
            item->b_safe = true;
            break;

        case VLC_CONFIG_DESC:
        {
            const char *text = va_arg (ap, const char *);
            const char *longtext = va_arg (ap, const char *);

371
372
            item->psz_text = text ? strdup (text) : NULL;
            item->psz_longtext = longtext ? strdup (longtext) : NULL;
373
374
375
            break;
        }

376
377
378
379
        case VLC_CONFIG_LIST:
        {
            size_t len = va_arg (ap, size_t);

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
380
381
            assert (item->list_count == 0); /* cannot replace choices */
            assert (item->list.psz_cb == NULL);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
382
383
            if (len == 0)
                break; /* nothing to do */
384
385
386
387
            /* Copy values */
            if (IsConfigIntegerType (item->i_type))
            {
                const int *src = va_arg (ap, const int *);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
388
                int *dst = xmalloc (sizeof (int) * len);
389

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
390
                memcpy (dst, src, sizeof (int) * len);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
391
                item->list.i = dst;
392
393
394
395
396
            }
            else
            if (IsConfigStringType (item->i_type))
            {
                const char *const *src = va_arg (ap, const char *const *);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
397
398
399
400
                char **dst = xmalloc (sizeof (char *) * len);

                for (size_t i = 0; i < len; i++)
                     dst[i] = src[i] ? strdup (src[i]) : NULL;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
401
                item->list.psz = dst;
402
403
404
405
406
407
            }
            else
                break;

            /* Copy textual descriptions */
            const char *const *text = va_arg (ap, const char *const *);
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
408
409
410
            char **dtext = xmalloc (sizeof (char *) * (len + 1));
            for (size_t i = 0; i < len; i++)
                dtext[i] = text[i] ? strdup (text[i]) : NULL;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
411
412
            item->list_text = dtext;
            item->list_count = len;
413
414
            break;
        }
415

416
        case VLC_CONFIG_LIST_CB:
417
418
419
420
421
422
423
            if (IsConfigIntegerType (item->i_type))
               item->list.i_cb = va_arg (ap, vlc_integer_list_cb);
            else
            if (IsConfigStringType (item->i_type))
               item->list.psz_cb = va_arg (ap, vlc_string_list_cb);
            else
                break;
424
425
            break;

426
        default:
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
427
428
            fprintf (stderr, "LibVLC: unknown module property %d\n", propid);
            fprintf (stderr, "LibVLC: too old to use this module?\n");
429
430
431
            ret = -1;
            break;
    }
432

433
434
435
    va_end (ap);
    return ret;
}
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451

/**
 * Runs a plug-in descriptor. This loads the plug-in meta-data in memory.
 */
module_t *vlc_plugin_describe (vlc_plugin_cb entry)
{
    module_t *module = NULL;

    if (entry (vlc_plugin_setter, &module) != 0)
    {
        if (module != NULL) /* partially initialized plug-in... */
            vlc_module_destroy (module);
        module = NULL;
    }
    return module;
}