Audacious  $Id:Doxyfile42802007-03-2104:39:00Znenolod$
plugin-registry.c
Go to the documentation of this file.
1 /*
2  * plugin-registry.c
3  * Copyright 2009-2011 John Lindgren
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice,
9  * this list of conditions, and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright notice,
12  * this list of conditions, and the following disclaimer in the documentation
13  * provided with the distribution.
14  *
15  * This software is provided "as is" and without any warranty, express or
16  * implied. In no event shall the authors be liable for any damages arising from
17  * the use of this software.
18  */
19 
20 /* While the registry is being built (during early startup) or destroyed (during
21  * late shutdown), the registry_locked flag will be set. Once this flag is
22  * cleared, the registry will not be modified and can be read by concurrent
23  * threads. The one change that can happen during this time is that a plugin is
24  * loaded; hence the mutex must be locked before checking that a plugin is
25  * loaded and while loading it. */
26 
27 #include <glib.h>
28 #include <pthread.h>
29 #include <stdio.h>
30 #include <string.h>
31 
32 #include <libaudcore/audstrings.h>
33 
34 #include "debug.h"
35 #include "i18n.h"
36 #include "interface.h"
37 #include "misc.h"
38 #include "plugin.h"
39 #include "plugins.h"
40 
41 #define FILENAME "plugin-registry"
42 #define FORMAT 8
43 
44 typedef struct {
45  GList * schemes;
47 
48 typedef struct {
49  GList * exts;
51 
52 typedef struct {
53  GList * keys[INPUT_KEYS];
54  bool_t has_images, has_subtunes, can_write_tuple, has_infowin;
56 
57 struct PluginHandle {
58  char * path;
61  Plugin * header;
62  char * name, * domain;
63  int priority;
65  GList * watches;
66  void * misc;
67 
68  union {
72  } u;
73 };
74 
75 typedef struct {
77  void * data;
78 } PluginWatch;
79 
80 static const char * plugin_type_names[] = {
81  [PLUGIN_TYPE_TRANSPORT] = "transport",
82  [PLUGIN_TYPE_PLAYLIST] = "playlist",
83  [PLUGIN_TYPE_INPUT] = "input",
84  [PLUGIN_TYPE_EFFECT] = "effect",
85  [PLUGIN_TYPE_OUTPUT] = "output",
86  [PLUGIN_TYPE_VIS] = "vis",
87  [PLUGIN_TYPE_GENERAL] = "general",
88  [PLUGIN_TYPE_IFACE] = "iface"};
89 
90 static const char * input_key_names[] = {
91  [INPUT_KEY_SCHEME] = "scheme",
92  [INPUT_KEY_EXTENSION] = "ext",
93  [INPUT_KEY_MIME] = "mime"};
94 
95 static GList * plugin_list = NULL;
97 static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
98 
99 static PluginHandle * plugin_new (char * path, bool_t confirmed, bool_t
100  loaded, int timestamp, int type, Plugin * header)
101 {
102  PluginHandle * plugin = g_malloc (sizeof (PluginHandle));
103 
104  plugin->path = path;
105  plugin->confirmed = confirmed;
106  plugin->loaded = loaded;
107  plugin->timestamp = timestamp;
108  plugin->type = type;
109  plugin->header = header;
110  plugin->name = NULL;
111  plugin->domain = NULL;
112  plugin->priority = 0;
113  plugin->has_about = FALSE;
114  plugin->has_configure = FALSE;
115  plugin->enabled = FALSE;
116  plugin->watches = NULL;
117  plugin->misc = NULL;
118 
119  if (type == PLUGIN_TYPE_TRANSPORT)
120  {
121  plugin->enabled = TRUE;
122  plugin->u.t.schemes = NULL;
123  }
124  else if (type == PLUGIN_TYPE_PLAYLIST)
125  {
126  plugin->enabled = TRUE;
127  plugin->u.p.exts = NULL;
128  }
129  else if (type == PLUGIN_TYPE_INPUT)
130  {
131  plugin->enabled = TRUE;
132  memset (plugin->u.i.keys, 0, sizeof plugin->u.i.keys);
133  plugin->u.i.has_images = FALSE;
134  plugin->u.i.has_subtunes = FALSE;
135  plugin->u.i.can_write_tuple = FALSE;
136  plugin->u.i.has_infowin = FALSE;
137  }
138 
139  plugin_list = g_list_prepend (plugin_list, plugin);
140  return plugin;
141 }
142 
144 {
145  plugin_list = g_list_remove (plugin_list, plugin);
146 
147  g_list_free_full (plugin->watches, g_free);
148 
149  if (plugin->type == PLUGIN_TYPE_TRANSPORT)
150  g_list_free_full (plugin->u.t.schemes, g_free);
151  else if (plugin->type == PLUGIN_TYPE_PLAYLIST)
152  g_list_free_full (plugin->u.p.exts, g_free);
153  else if (plugin->type == PLUGIN_TYPE_INPUT)
154  {
155  for (int key = 0; key < INPUT_KEYS; key ++)
156  g_list_free_full (plugin->u.i.keys[key], g_free);
157  }
158 
159  g_free (plugin->path);
160  g_free (plugin->name);
161  g_free (plugin->domain);
162  g_free (plugin->misc);
163  g_free (plugin);
164 }
165 
166 static FILE * open_registry_file (const char * mode)
167 {
168  char * path = g_strdup_printf ("%s/" FILENAME, get_path (AUD_PATH_USER_DIR));
169  FILE * file = fopen (path, mode);
170  g_free (path);
171  return file;
172 }
173 
174 static void transport_plugin_save (PluginHandle * plugin, FILE * handle)
175 {
176  for (GList * node = plugin->u.t.schemes; node; node = node->next)
177  fprintf (handle, "scheme %s\n", (const char *) node->data);
178 }
179 
180 static void playlist_plugin_save (PluginHandle * plugin, FILE * handle)
181 {
182  for (GList * node = plugin->u.p.exts; node; node = node->next)
183  fprintf (handle, "ext %s\n", (const char *) node->data);
184 }
185 
186 static void input_plugin_save (PluginHandle * plugin, FILE * handle)
187 {
188  for (int key = 0; key < INPUT_KEYS; key ++)
189  {
190  for (GList * node = plugin->u.i.keys[key]; node; node = node->next)
191  fprintf (handle, "%s %s\n", input_key_names[key], (const char *)
192  node->data);
193  }
194 
195  fprintf (handle, "images %d\n", plugin->u.i.has_images);
196  fprintf (handle, "subtunes %d\n", plugin->u.i.has_subtunes);
197  fprintf (handle, "writes %d\n", plugin->u.i.can_write_tuple);
198  fprintf (handle, "infowin %d\n", plugin->u.i.has_infowin);
199 }
200 
201 static void plugin_save (PluginHandle * plugin, FILE * handle)
202 {
203  fprintf (handle, "%s %s\n", plugin_type_names[plugin->type], plugin->path);
204  fprintf (handle, "stamp %d\n", plugin->timestamp);
205  fprintf (handle, "name %s\n", plugin->name);
206 
207  if (plugin->domain)
208  fprintf (handle, "domain %s\n", plugin->domain);
209 
210  fprintf (handle, "priority %d\n", plugin->priority);
211  fprintf (handle, "about %d\n", plugin->has_about);
212  fprintf (handle, "config %d\n", plugin->has_configure);
213  fprintf (handle, "enabled %d\n", plugin->enabled);
214 
215  if (plugin->type == PLUGIN_TYPE_TRANSPORT)
216  transport_plugin_save (plugin, handle);
217  else if (plugin->type == PLUGIN_TYPE_PLAYLIST)
218  playlist_plugin_save (plugin, handle);
219  else if (plugin->type == PLUGIN_TYPE_INPUT)
220  input_plugin_save (plugin, handle);
221 }
222 
224 {
225  FILE * handle = open_registry_file ("w");
226  g_return_if_fail (handle);
227 
228  fprintf (handle, "format %d\n", FORMAT);
229 
230  g_list_foreach (plugin_list, (GFunc) plugin_save, handle);
231  fclose (handle);
232 
233  g_list_foreach (plugin_list, (GFunc) plugin_free, NULL);
235 }
236 
237 static char parse_key[512];
238 static char * parse_value;
239 
240 static void parse_next (FILE * handle)
241 {
242  parse_value = NULL;
243 
244  if (! fgets (parse_key, sizeof parse_key, handle))
245  return;
246 
247  char * space = strchr (parse_key, ' ');
248  if (! space)
249  return;
250 
251  * space = 0;
252  parse_value = space + 1;
253 
254  char * newline = strchr (parse_value, '\n');
255  if (newline)
256  * newline = 0;
257 }
258 
259 static bool_t parse_integer (const char * key, int * value)
260 {
261  return (parse_value && ! strcmp (parse_key, key) && sscanf (parse_value,
262  "%d", value) == 1);
263 }
264 
265 static char * parse_string (const char * key)
266 {
267  return (parse_value && ! strcmp (parse_key, key)) ? g_strdup (parse_value) :
268  NULL;
269 }
270 
271 static void transport_plugin_parse (PluginHandle * plugin, FILE * handle)
272 {
273  char * value;
274  while ((value = parse_string ("scheme")))
275  {
276  plugin->u.t.schemes = g_list_prepend (plugin->u.t.schemes, value);
277  parse_next (handle);
278  }
279 }
280 
281 static void playlist_plugin_parse (PluginHandle * plugin, FILE * handle)
282 {
283  char * value;
284  while ((value = parse_string ("ext")))
285  {
286  plugin->u.p.exts = g_list_prepend (plugin->u.p.exts, value);
287  parse_next (handle);
288  }
289 }
290 
291 static void input_plugin_parse (PluginHandle * plugin, FILE * handle)
292 {
293  for (int key = 0; key < INPUT_KEYS; key ++)
294  {
295  char * value;
296  while ((value = parse_string (input_key_names[key])))
297  {
298  plugin->u.i.keys[key] = g_list_prepend (plugin->u.i.keys[key],
299  value);
300  parse_next (handle);
301  }
302  }
303 
304  if (parse_integer ("images", & plugin->u.i.has_images))
305  parse_next (handle);
306  if (parse_integer ("subtunes", & plugin->u.i.has_subtunes))
307  parse_next (handle);
308  if (parse_integer ("writes", & plugin->u.i.can_write_tuple))
309  parse_next (handle);
310  if (parse_integer ("infowin", & plugin->u.i.has_infowin))
311  parse_next (handle);
312 }
313 
314 static bool_t plugin_parse (FILE * handle)
315 {
316  char * path = NULL;
317 
318  int type;
319  for (type = 0; type < PLUGIN_TYPES; type ++)
320  {
321  if ((path = parse_string (plugin_type_names[type])))
322  goto FOUND;
323  }
324 
325  return FALSE;
326 
327 FOUND:
328  parse_next (handle);
329 
330  int timestamp;
331  if (! parse_integer ("stamp", & timestamp))
332  {
333  g_free (path);
334  return FALSE;
335  }
336 
337  PluginHandle * plugin = plugin_new (path, FALSE, FALSE, timestamp, type,
338  NULL);
339  parse_next (handle);
340 
341  if ((plugin->name = parse_string ("name")))
342  parse_next (handle);
343  if ((plugin->domain = parse_string ("domain")))
344  parse_next (handle);
345  if (parse_integer ("priority", & plugin->priority))
346  parse_next (handle);
347  if (parse_integer ("about", & plugin->has_about))
348  parse_next (handle);
349  if (parse_integer ("config", & plugin->has_configure))
350  parse_next (handle);
351  if (parse_integer ("enabled", & plugin->enabled))
352  parse_next (handle);
353 
354  if (type == PLUGIN_TYPE_TRANSPORT)
355  transport_plugin_parse (plugin, handle);
356  else if (type == PLUGIN_TYPE_PLAYLIST)
357  playlist_plugin_parse (plugin, handle);
358  else if (type == PLUGIN_TYPE_INPUT)
359  input_plugin_parse (plugin, handle);
360 
361  return TRUE;
362 }
363 
365 {
366  FILE * handle = open_registry_file ("r");
367  if (! handle)
368  goto UNLOCK;
369 
370  parse_next (handle);
371 
372  int format;
373  if (! parse_integer ("format", & format) || format != FORMAT)
374  goto ERR;
375 
376  parse_next (handle);
377 
378  while (plugin_parse (handle))
379  ;
380 
381 ERR:
382  fclose (handle);
383 UNLOCK:
385 }
386 
388 {
389  if (plugin->confirmed)
390  return;
391 
392  AUDDBG ("Plugin not found: %s\n", plugin->path);
393  plugin_free (plugin);
394 }
395 
397 {
398  if (a->type < b->type)
399  return -1;
400  if (a->type > b->type)
401  return 1;
402  if (a->priority < b->priority)
403  return -1;
404  if (a->priority > b->priority)
405  return 1;
406 
407  int diff;
408  if ((diff = string_compare (dgettext (a->domain, a->name), dgettext (b->domain, b->name))))
409  return diff;
410 
411  return string_compare (a->path, b->path);
412 }
413 
415 {
416  g_list_foreach (plugin_list, (GFunc) plugin_prune, NULL);
417  plugin_list = g_list_sort (plugin_list, (GCompareFunc) plugin_compare);
419 }
420 
421 static int plugin_lookup_cb (PluginHandle * plugin, const char * path)
422 {
423  return strcmp (plugin->path, path);
424 }
425 
426 PluginHandle * plugin_lookup (const char * path)
427 {
428  GList * node = g_list_find_custom (plugin_list, path, (GCompareFunc)
430  return node ? node->data : NULL;
431 }
432 
433 static int plugin_lookup_basename_cb (PluginHandle * plugin, const char * basename)
434 {
435  char * test = g_path_get_basename (plugin->path);
436 
437  char * dot = strrchr (test, '.');
438  if (dot)
439  * dot = 0;
440 
441  int ret = strcmp (test, basename);
442 
443  g_free (test);
444  return ret;
445 }
446 
447 /* Note: If there are multiple plugins with the same basename, this returns only
448  * one of them. So give different plugins different basenames. --jlindgren */
449 PluginHandle * plugin_lookup_basename (const char * basename)
450 {
451  GList * node = g_list_find_custom (plugin_list, basename, (GCompareFunc)
453  return node ? node->data : NULL;
454 }
455 
457 {
458  Plugin * header = plugin->header;
459 
460  g_free (plugin->name);
461  g_free (plugin->domain);
462  plugin->name = g_strdup (header->name);
463  plugin->domain = PLUGIN_HAS_FUNC (header, domain) ? g_strdup (header->domain) : NULL;
464  plugin->has_about = PLUGIN_HAS_FUNC (header, about) || PLUGIN_HAS_FUNC (header, about_text);
465  plugin->has_configure = PLUGIN_HAS_FUNC (header, configure) || PLUGIN_HAS_FUNC (header, prefs);
466 
467  if (header->type == PLUGIN_TYPE_TRANSPORT)
468  {
469  TransportPlugin * tp = (TransportPlugin *) header;
470 
471  g_list_free_full (plugin->u.t.schemes, g_free);
472  plugin->u.t.schemes = NULL;
473 
474  for (int i = 0; tp->schemes[i]; i ++)
475  plugin->u.t.schemes = g_list_prepend (plugin->u.t.schemes, g_strdup
476  (tp->schemes[i]));
477  }
478  else if (header->type == PLUGIN_TYPE_PLAYLIST)
479  {
480  PlaylistPlugin * pp = (PlaylistPlugin *) header;
481 
482  g_list_free_full (plugin->u.p.exts, g_free);
483  plugin->u.p.exts = NULL;
484 
485  for (int i = 0; pp->extensions[i]; i ++)
486  plugin->u.p.exts = g_list_prepend (plugin->u.p.exts, g_strdup
487  (pp->extensions[i]));
488  }
489  else if (header->type == PLUGIN_TYPE_INPUT)
490  {
491  InputPlugin * ip = (InputPlugin *) header;
492  plugin->priority = ip->priority;
493 
494  for (int key = 0; key < INPUT_KEYS; key ++)
495  {
496  g_list_free_full (plugin->u.i.keys[key], g_free);
497  plugin->u.i.keys[key] = NULL;
498  }
499 
500  if (PLUGIN_HAS_FUNC (ip, extensions))
501  {
502  for (int i = 0; ip->extensions[i]; i ++)
503  plugin->u.i.keys[INPUT_KEY_EXTENSION] = g_list_prepend
504  (plugin->u.i.keys[INPUT_KEY_EXTENSION], g_strdup
505  (ip->extensions[i]));
506  }
507 
508  if (PLUGIN_HAS_FUNC (ip, mimes))
509  {
510  for (int i = 0; ip->mimes[i]; i ++)
511  plugin->u.i.keys[INPUT_KEY_MIME] = g_list_prepend
512  (plugin->u.i.keys[INPUT_KEY_MIME], g_strdup (ip->mimes[i]));
513  }
514 
515  if (PLUGIN_HAS_FUNC (ip, schemes))
516  {
517  for (int i = 0; ip->schemes[i]; i ++)
518  plugin->u.i.keys[INPUT_KEY_SCHEME] = g_list_prepend
519  (plugin->u.i.keys[INPUT_KEY_SCHEME], g_strdup (ip->schemes[i]));
520  }
521 
522  plugin->u.i.has_images = PLUGIN_HAS_FUNC (ip, get_song_image);
523  plugin->u.i.has_subtunes = ip->have_subtune;
524  plugin->u.i.can_write_tuple = PLUGIN_HAS_FUNC (ip, update_song_tuple);
525  plugin->u.i.has_infowin = PLUGIN_HAS_FUNC (ip, file_info_box);
526  }
527  else if (header->type == PLUGIN_TYPE_OUTPUT)
528  {
529  OutputPlugin * op = (OutputPlugin *) header;
530  plugin->priority = 10 - op->probe_priority;
531  }
532  else if (header->type == PLUGIN_TYPE_EFFECT)
533  {
534  EffectPlugin * ep = (EffectPlugin *) header;
535  plugin->priority = ep->order;
536  }
537  else if (header->type == PLUGIN_TYPE_GENERAL)
538  {
539  GeneralPlugin * gp = (GeneralPlugin *) header;
540  if (new)
541  plugin->enabled = gp->enabled_by_default;
542  }
543 }
544 
545 void plugin_register (const char * path, int timestamp)
546 {
547  PluginHandle * plugin = plugin_lookup (path);
548 
549  if (plugin)
550  {
551  AUDDBG ("Register plugin: %s\n", path);
552  plugin->confirmed = TRUE;
553 
554  if (plugin->timestamp != timestamp)
555  {
556  AUDDBG ("Rescan plugin: %s\n", path);
557  Plugin * header = plugin_load (path);
558  if (! header || header->type != plugin->type)
559  return;
560 
561  plugin->loaded = TRUE;
562  plugin->header = header;
563  plugin->timestamp = timestamp;
564 
565  plugin_get_info (plugin, FALSE);
566  }
567  }
568  else
569  {
570  AUDDBG ("New plugin: %s\n", path);
571  Plugin * header = plugin_load (path);
572  if (! header)
573  return;
574 
575  plugin = plugin_new (g_strdup (path), TRUE, TRUE, timestamp,
576  header->type, header);
577 
578  plugin_get_info (plugin, TRUE);
579  }
580 }
581 
583 {
584  return plugin->type;
585 }
586 
588 {
589  return plugin->path;
590 }
591 
593 {
594  pthread_mutex_lock (& mutex);
595 
596  if (! plugin->loaded)
597  {
598  Plugin * header = plugin_load (plugin->path);
599  if (! header || header->type != plugin->type)
600  goto DONE;
601 
602  plugin->loaded = TRUE;
603  plugin->header = header;
604  }
605 
606 DONE:
607  pthread_mutex_unlock (& mutex);
608  return plugin->header;
609 }
610 
611 static int plugin_by_header_cb (PluginHandle * plugin, const void * header)
612 {
613  return (plugin->header == header) ? 0 : -1;
614 }
615 
616 PluginHandle * plugin_by_header (const void * header)
617 {
618  GList * node = g_list_find_custom (plugin_list, header, (GCompareFunc)
620  return node ? node->data : NULL;
621 }
622 
623 void plugin_for_each (int type, PluginForEachFunc func, void * data)
624 {
625  for (GList * node = plugin_list; node; node = node->next)
626  {
627  if (((PluginHandle *) node->data)->type != type)
628  continue;
629  if (! func (node->data, data))
630  break;
631  }
632 }
633 
635 {
636  return dgettext (plugin->domain, plugin->name);
637 }
638 
640 {
641  return plugin->has_about;
642 }
643 
645 {
646  return plugin->has_configure;
647 }
648 
650 {
651  return plugin->enabled;
652 }
653 
655 {
656  for (GList * node = plugin->watches; node; )
657  {
658  GList * next = node->next;
659  PluginWatch * watch = node->data;
660 
661  if (! watch->func (plugin, watch->data))
662  {
663  g_free (watch);
664  plugin->watches = g_list_delete_link (plugin->watches, node);
665  }
666 
667  node = next;
668  }
669 }
670 
672 {
673  plugin->enabled = enabled;
674  plugin_call_watches (plugin);
675 }
676 
677 typedef struct {
679  void * data;
681 
683  PluginForEnabledState * state)
684 {
685  if (! plugin->enabled)
686  return TRUE;
687  return state->func (plugin, state->data);
688 }
689 
691 {
692  PluginForEnabledState state = {func, data};
694 }
695 
697  data)
698 {
699  PluginWatch * watch = g_malloc (sizeof (PluginWatch));
700  watch->func = func;
701  watch->data = data;
702  plugin->watches = g_list_prepend (plugin->watches, watch);
703 }
704 
706  data)
707 {
708  for (GList * node = plugin->watches; node; )
709  {
710  GList * next = node->next;
711  PluginWatch * watch = node->data;
712 
713  if (watch->func == func && watch->data == data)
714  {
715  g_free (watch);
716  plugin->watches = g_list_delete_link (plugin->watches, node);
717  }
718 
719  node = next;
720  }
721 }
722 
724 {
725  if (! plugin->misc)
726  plugin->misc = g_malloc0 (size);
727 
728  return plugin->misc;
729 }
730 
731 typedef struct {
732  const char * scheme;
735 
738 {
739  if (! g_list_find_custom (plugin->u.t.schemes, state->scheme,
740  (GCompareFunc) g_ascii_strcasecmp))
741  return TRUE;
742 
743  state->plugin = plugin;
744  return FALSE;
745 }
746 
748 {
749  TransportPluginForSchemeState state = {scheme, NULL};
752  return state.plugin;
753 }
754 
755 typedef struct {
756  const char * ext;
759 
762 {
763  if (! g_list_find_custom (plugin->u.p.exts, state->ext,
764  (GCompareFunc) g_ascii_strcasecmp))
765  return TRUE;
766 
767  state->plugin = plugin;
768  return FALSE;
769 }
770 
771 PluginHandle * playlist_plugin_for_extension (const char * extension)
772 {
773  PlaylistPluginForExtState state = {extension, NULL};
775  playlist_plugin_for_ext_cb, & state);
776  return state.plugin;
777 }
778 
779 typedef struct {
780  int key;
781  const char * value;
783  void * data;
785 
787  InputPluginForKeyState * state)
788 {
789  if (! g_list_find_custom (plugin->u.i.keys[state->key], state->value,
790  (GCompareFunc) g_ascii_strcasecmp))
791  return TRUE;
792 
793  return state->func (plugin, state->data);
794 }
795 
796 void input_plugin_for_key (int key, const char * value, PluginForEachFunc
797  func, void * data)
798 {
799  InputPluginForKeyState state = {key, value, func, data};
801  input_plugin_for_key_cb, & state);
802 }
803 
805 {
806  g_return_val_if_fail (plugin->type == PLUGIN_TYPE_INPUT, FALSE);
807  return plugin->u.i.has_images;
808 }
809 
811 {
812  g_return_val_if_fail (plugin->type == PLUGIN_TYPE_INPUT, FALSE);
813  return plugin->u.i.has_subtunes;
814 }
815 
817 {
818  g_return_val_if_fail (plugin->type == PLUGIN_TYPE_INPUT, FALSE);
819  return plugin->u.i.can_write_tuple;
820 }
821 
823 {
824  g_return_val_if_fail (plugin->type == PLUGIN_TYPE_INPUT, FALSE);
825  return plugin->u.i.has_infowin;
826 }
bool_t plugin_get_enabled(PluginHandle *plugin)
static void transport_plugin_parse(PluginHandle *plugin, FILE *handle)
bool_t input_plugin_has_images(PluginHandle *plugin)
void plugin_set_enabled(PluginHandle *plugin, bool_t enabled)
int plugin_compare(PluginHandle *a, PluginHandle *b)
static const char * plugin_type_names[]
static const char * input_key_names[]
union PluginHandle::@21 u
static float a[EQ_BANDS][2]
Definition: equalizer.c:55
static int plugin_by_header_cb(PluginHandle *plugin, const void *header)
static void parse_next(FILE *handle)
void plugin_register(const char *path, int timestamp)
static bool_t plugin_for_enabled_cb(PluginHandle *plugin, PluginForEnabledState *state)
static void plugin_call_watches(PluginHandle *plugin)
void plugin_registry_prune(void)
Plugin * plugin_load(const char *filename)
Definition: pluginenum.c:61
void input_plugin_for_key(int key, const char *value, PluginForEachFunc func, void *data)
void plugin_remove_watch(PluginHandle *plugin, PluginForEachFunc func, void *data)
PluginHandle * plugin_lookup_basename(const char *basename)
static FILE * open_registry_file(const char *mode)
int format
Definition: audio.c:132
static float b[EQ_BANDS][2]
Definition: equalizer.c:56
#define PLUGIN_HAS_FUNC(p, func)
Definition: plugin.h:515
type
Definition: plugins-api.h:41
bool_t input_plugin_can_write_tuple(PluginHandle *plugin)
static bool_t registry_locked
static bool_t transport_plugin_for_scheme_cb(PluginHandle *plugin, TransportPluginForSchemeState *state)
#define FALSE
Definition: core.h:37
PluginHandle * playlist_plugin_for_extension(const char *extension)
EXPORT int string_compare(const char *ap, const char *bp)
Definition: audstrings.c:282
static void plugin_prune(PluginHandle *plugin)
static PluginHandle * plugin_new(char *path, bool_t confirmed, bool_t loaded, int timestamp, int type, Plugin *header)
PluginForEachFunc func
Index Index bool_t
Definition: playlist-api.h:122
static bool_t enabled
Definition: vis_runner.c:38
PlaylistPluginData p
#define AUDDBG(...)
Definition: debug.h:30
static void input_plugin_save(PluginHandle *plugin, FILE *handle)
const void * plugin_get_header(PluginHandle *plugin)
static char * parse_value
InputPluginData i
void plugin_registry_load(void)
void plugin_registry_save(void)
static bool_t parse_integer(const char *key, int *value)
#define NULL
Definition: core.h:29
bool_t input_plugin_has_infowin(PluginHandle *plugin)
static void playlist_plugin_save(PluginHandle *plugin, FILE *handle)
void * plugin_get_misc_data(PluginHandle *plugin, int size)
bool_t has_configure
bool_t plugin_has_about(PluginHandle *plugin)
static void plugin_get_info(PluginHandle *plugin, bool_t new)
bool_t plugin_has_configure(PluginHandle *plugin)
bool_t(* PluginForEachFunc)(PluginHandle *plugin, void *data)
Definition: plugins.h:27
#define TRUE
Definition: core.h:39
static void transport_plugin_save(PluginHandle *plugin, FILE *handle)
static bool_t playlist_plugin_for_ext_cb(PluginHandle *plugin, PlaylistPluginForExtState *state)
static int plugin_lookup_cb(PluginHandle *plugin, const char *path)
GList * keys[INPUT_KEYS]
PluginForEachFunc func
func
Definition: plugins-api.h:41
static bool_t loaded
Definition: history.c:32
static void plugin_save(PluginHandle *plugin, FILE *handle)
static char parse_key[512]
static bool_t plugin_parse(FILE *handle)
const char * get_path(int id)
Definition: main.c:225
static GList * plugin_list
PluginHandle * transport_plugin_for_scheme(const char *scheme)
static void plugin_free(PluginHandle *plugin)
static int plugin_lookup_basename_cb(PluginHandle *plugin, const char *basename)
Plugin * header
#define FILENAME
void plugin_for_enabled(int type, PluginForEachFunc func, void *data)
#define FORMAT
PluginForEachFunc func
const char * plugin_get_filename(PluginHandle *plugin)
static pthread_mutex_t mutex
bool_t input_plugin_has_subtunes(PluginHandle *plugin)
TransportPluginData t
void data PluginHandle plugin
Definition: plugins-api.h:54
static bool_t input_plugin_for_key_cb(PluginHandle *plugin, InputPluginForKeyState *state)
void plugin_for_each(int type, PluginForEachFunc func, void *data)
PluginHandle * plugin_by_header(const void *header)
const char * plugin_get_name(PluginHandle *plugin)
PluginHandle * plugin_lookup(const char *path)
static void playlist_plugin_parse(PluginHandle *plugin, FILE *handle)
int plugin_get_type(PluginHandle *plugin)
static void input_plugin_parse(PluginHandle *plugin, FILE *handle)
void plugin_add_watch(PluginHandle *plugin, PluginForEachFunc func, void *data)
static char * parse_string(const char *key)