]> git.sesse.net Git - vlc/blob - src/misc/objects.c
Fix the use of commands list, tree and vars in the rc interface which were broken...
[vlc] / src / misc / objects.c
1 /*****************************************************************************
2  * objects.c: vlc_object_t handling
3  *****************************************************************************
4  * Copyright (C) 2004-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /**
25  * \file
26  * This file contains the functions to handle the vlc_object_t type
27  */
28
29
30 /*****************************************************************************
31  * Preamble
32  *****************************************************************************/
33 #include <vlc/vlc.h>
34
35 #include "../libvlc.h"
36 #include <vlc_vout.h>
37 #include <vlc_aout.h>
38 #include "audio_output/aout_internal.h"
39
40 #include <vlc_access.h>
41 #include <vlc_demux.h>
42 #include <vlc_stream.h>
43
44 #include <vlc_sout.h>
45 #include "stream_output/stream_output.h"
46
47 #include "vlc_playlist.h"
48 #include "vlc_interface.h"
49 #include "vlc_codec.h"
50 #include "vlc_filter.h"
51
52 #include "vlc_httpd.h"
53 #include "vlc_vlm.h"
54 #include "input/vlm_internal.h"
55 #include "vlc_vod.h"
56 #include "vlc_tls.h"
57 #include "vlc_xml.h"
58 #include "vlc_osd.h"
59 #include "vlc_meta.h"
60
61 #include "variables.h"
62
63 /*****************************************************************************
64  * Local prototypes
65  *****************************************************************************/
66 static int  DumpCommand( vlc_object_t *, char const *,
67                          vlc_value_t, vlc_value_t, void * );
68
69 static vlc_object_t * FindObject    ( vlc_object_t *, int, int );
70 static vlc_object_t * FindObjectName( vlc_object_t *, const char *, int );
71 static void           DetachObject  ( vlc_object_t * );
72 static void           PrintObject   ( vlc_object_t *, const char * );
73 static void           DumpStructure ( vlc_object_t *, int, char * );
74 static int            FindIndex     ( vlc_object_t *, vlc_object_t **, int );
75 static void           SetAttachment ( vlc_object_t *, vlc_bool_t );
76
77 static vlc_list_t   * NewList       ( int );
78 static void           ListReplace   ( vlc_list_t *, vlc_object_t *, int );
79 /*static void           ListAppend    ( vlc_list_t *, vlc_object_t * );*/
80 static int            CountChildren ( vlc_object_t *, int );
81 static void           ListChildren  ( vlc_list_t *, vlc_object_t *, int );
82
83 /*****************************************************************************
84  * Local structure lock
85  *****************************************************************************/
86 static vlc_mutex_t    structure_lock;
87 static vlc_object_internals_t global_internals;
88
89 vlc_object_t *vlc_custom_create( vlc_object_t *p_this, size_t i_size,
90                                  int i_type, const char *psz_type )
91 {
92     vlc_object_t *p_new;
93     vlc_object_internals_t *p_priv;
94
95     if( i_type == VLC_OBJECT_GLOBAL )
96     {
97         p_new = p_this;
98         p_priv = &global_internals;
99         memset( p_priv, 0, sizeof( *p_priv ) );
100     }
101     else
102     {
103         p_priv = calloc( 1, sizeof( *p_priv ) + i_size );
104         if( p_priv == NULL )
105             return NULL;
106
107         p_new = (vlc_object_t *)(p_priv + 1);
108     }
109
110     p_new->p_internals = p_priv;
111     p_new->i_object_type = i_type;
112     p_new->psz_object_type = psz_type;
113
114     p_new->psz_object_name = NULL;
115
116     p_new->b_die = VLC_FALSE;
117     p_new->b_error = VLC_FALSE;
118     p_new->b_dead = VLC_FALSE;
119     p_priv->b_attached = VLC_FALSE;
120     p_new->b_force = VLC_FALSE;
121
122     p_new->psz_header = NULL;
123
124     if( p_this->i_flags & OBJECT_FLAGS_NODBG )
125         p_new->i_flags |= OBJECT_FLAGS_NODBG;
126     if( p_this->i_flags & OBJECT_FLAGS_QUIET )
127         p_new->i_flags |= OBJECT_FLAGS_QUIET;
128     if( p_this->i_flags & OBJECT_FLAGS_NOINTERACT )
129         p_new->i_flags |= OBJECT_FLAGS_NOINTERACT;
130
131     p_priv->p_vars = calloc( sizeof( variable_t ), 16 );
132
133     if( !p_priv->p_vars )
134     {
135         if( i_type != VLC_OBJECT_GLOBAL )
136             free( p_priv );
137         return NULL;
138     }
139
140     if( i_type == VLC_OBJECT_GLOBAL )
141     {
142         /* If i_type is global, then p_new is actually p_libvlc_global */
143         libvlc_global_data_t *p_libvlc_global = (libvlc_global_data_t *)p_new;
144         p_new->p_libvlc = NULL;
145
146         p_libvlc_global->i_counter = 0;
147         p_new->i_object_id = 0;
148
149         p_libvlc_global->i_objects = 1;
150         p_libvlc_global->pp_objects = malloc( sizeof(vlc_object_t *) );
151         p_libvlc_global->pp_objects[0] = p_new;
152         p_priv->b_attached = VLC_TRUE;
153     }
154     else
155     {
156         libvlc_global_data_t *p_libvlc_global = vlc_global();
157         if( i_type == VLC_OBJECT_LIBVLC )
158         {
159             p_new->p_libvlc = (libvlc_int_t*)p_new;
160             p_priv->b_attached = VLC_TRUE;
161         }
162         else
163         {
164             p_new->p_libvlc = p_this->p_libvlc;
165         }
166
167         vlc_mutex_lock( &structure_lock );
168
169         p_libvlc_global->i_counter++;
170         p_new->i_object_id = p_libvlc_global->i_counter;
171
172         /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
173          * useless to try and recover anything if pp_objects gets smashed. */
174         TAB_APPEND( p_libvlc_global->i_objects, p_libvlc_global->pp_objects,
175                     p_new );
176
177         vlc_mutex_unlock( &structure_lock );
178     }
179
180     p_new->i_refcount = 0;
181     p_new->p_parent = NULL;
182     p_new->pp_children = NULL;
183     p_new->i_children = 0;
184
185     p_new->p_private = NULL;
186
187     /* Initialize mutexes and condvars */
188     vlc_mutex_init( p_new, &p_new->object_lock );
189     vlc_cond_init( p_new, &p_new->object_wait );
190     vlc_mutex_init( p_new, &p_priv->var_lock );
191
192     if( i_type == VLC_OBJECT_GLOBAL )
193     {
194         vlc_mutex_init( p_new, &structure_lock );
195     }
196
197     if( i_type == VLC_OBJECT_LIBVLC )
198     {
199         var_Create( p_new, "list", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
200         var_AddCallback( p_new, "list", DumpCommand, NULL );
201         var_Create( p_new, "tree", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
202         var_AddCallback( p_new, "tree", DumpCommand, NULL );
203         var_Create( p_new, "vars", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
204         var_AddCallback( p_new, "vars", DumpCommand, NULL );
205     }
206
207     return p_new;
208 }
209
210
211 /**
212  * Allocates and initializes a vlc object.
213  *
214  * @param i_type known object type (all of them are negative integer values),
215  *               or object byte size (always positive).
216  *
217  * @return the new object, or NULL on error.
218  */
219 void * __vlc_object_create( vlc_object_t *p_this, int i_type )
220 {
221     const char   * psz_type;
222     size_t         i_size;
223
224     switch( i_type )
225     {
226         case VLC_OBJECT_GLOBAL:
227             i_size = sizeof(libvlc_global_data_t);
228             psz_type = "global";
229             break;
230         case VLC_OBJECT_LIBVLC:
231             i_size = sizeof(libvlc_int_t);
232             psz_type = "libvlc";
233             break;
234         case VLC_OBJECT_INTF:
235             i_size = sizeof(intf_thread_t);
236             psz_type = "interface";
237             break;
238         case VLC_OBJECT_DIALOGS:
239             i_size = sizeof(intf_thread_t);
240             psz_type = "dialogs";
241             break;
242         case VLC_OBJECT_PLAYLIST:
243             i_size = sizeof(playlist_t);
244             psz_type = "playlist";
245             break;
246         case VLC_OBJECT_SD:
247             i_size = sizeof(services_discovery_t);
248             psz_type = "services discovery";
249             break;
250         case VLC_OBJECT_INPUT:
251             i_size = sizeof(input_thread_t);
252             psz_type = "input";
253             break;
254         case VLC_OBJECT_DEMUX:
255             i_size = sizeof(demux_t);
256             psz_type = "demux";
257             break;
258         case VLC_OBJECT_ACCESS:
259             i_size = sizeof(access_t);
260             psz_type = "access";
261             break;
262         case VLC_OBJECT_DECODER:
263             i_size = sizeof(decoder_t);
264             psz_type = "decoder";
265             break;
266         case VLC_OBJECT_PACKETIZER:
267             i_size = sizeof(decoder_t);
268             psz_type = "packetizer";
269             break;
270         case VLC_OBJECT_ENCODER:
271             i_size = sizeof(encoder_t);
272             psz_type = "encoder";
273             break;
274         case VLC_OBJECT_FILTER:
275             i_size = sizeof(filter_t);
276             psz_type = "filter";
277             break;
278         case VLC_OBJECT_VOUT:
279             i_size = sizeof(vout_thread_t);
280             psz_type = "video output";
281             break;
282         case VLC_OBJECT_SPU:
283             i_size = sizeof(spu_t);
284             psz_type = "subpicture";
285             break;
286         case VLC_OBJECT_AOUT:
287             i_size = sizeof(aout_instance_t);
288             psz_type = "audio output";
289             break;
290         case VLC_OBJECT_SOUT:
291             i_size = sizeof(sout_instance_t);
292             psz_type = "stream output";
293             break;
294         case VLC_OBJECT_VLM:
295             i_size = sizeof( vlm_t );
296             psz_type = "vlm dameon";
297             break;
298         case VLC_OBJECT_VOD:
299             i_size = sizeof( vod_t );
300             psz_type = "vod server";
301             break;
302         case VLC_OBJECT_TLS:
303             i_size = sizeof( tls_t );
304             psz_type = "tls";
305             break;
306         case VLC_OBJECT_XML:
307             i_size = sizeof( xml_t );
308             psz_type = "xml";
309             break;
310         case VLC_OBJECT_OPENGL:
311             i_size = sizeof( vout_thread_t );
312             psz_type = "opengl";
313             break;
314         case VLC_OBJECT_ANNOUNCE:
315             i_size = sizeof( announce_handler_t );
316             psz_type = "announce";
317             break;
318         case VLC_OBJECT_META_ENGINE:
319             i_size = sizeof( meta_engine_t );
320             psz_type = "meta engine";
321             break;
322         case VLC_OBJECT_OSDMENU:
323             i_size = sizeof( osd_menu_t );
324             psz_type = "osd menu";
325             break;
326         default:
327             i_size = i_type > (int)sizeof(vlc_object_t)
328                          ? i_type : (int)sizeof(vlc_object_t);
329             i_type = VLC_OBJECT_GENERIC;
330             psz_type = "generic";
331             break;
332     }
333
334     return vlc_custom_create( p_this, i_size, i_type, psz_type );
335 }
336
337
338 /**
339  ****************************************************************************
340  * Destroy a vlc object
341  *
342  * This function destroys an object that has been previously allocated with
343  * vlc_object_create. The object's refcount must be zero and it must not be
344  * attached to other objects in any way.
345  *****************************************************************************/
346 void __vlc_object_destroy( vlc_object_t *p_this )
347 {
348     vlc_object_internals_t *p_priv = vlc_internals( p_this );
349     int i_delay = 0;
350
351     if( p_this->i_children )
352     {
353         msg_Err( p_this, "cannot delete object (%i, %s) with children" ,
354                  p_this->i_object_id, p_this->psz_object_name );
355         return;
356     }
357
358     if( p_this->p_parent )
359     {
360         msg_Err( p_this, "cannot delete object (%i, %s) with a parent",
361                  p_this->i_object_id, p_this->psz_object_name );
362         return;
363     }
364
365     while( p_this->i_refcount )
366     {
367         i_delay++;
368
369         /* Don't warn immediately ... 100ms seems OK */
370         if( i_delay == 2 )
371         {
372             msg_Warn( p_this,
373                   "refcount is %i, delaying before deletion (id=%d,type=%d)",
374                   p_this->i_refcount, p_this->i_object_id,
375                   p_this->i_object_type );
376         }
377         else if( i_delay == 10 )
378         {
379             msg_Err( p_this,
380                   "refcount is %i, delaying again (id=%d,type=%d)",
381                   p_this->i_refcount, p_this->i_object_id,
382                   p_this->i_object_type );
383         }
384         else if( i_delay == 20 )
385         {
386             msg_Err( p_this,
387                   "waited too long, cancelling destruction (id=%d,type=%d)",
388                   p_this->i_object_id, p_this->i_object_type );
389             return;
390         }
391
392         msleep( 100000 );
393     }
394
395     /* Destroy the associated variables, starting from the end so that
396      * no memmove calls have to be done. */
397     while( p_priv->i_vars )
398     {
399         var_Destroy( p_this, p_priv->p_vars[p_priv->i_vars - 1].psz_name );
400     }
401
402     free( p_priv->p_vars );
403     vlc_mutex_destroy( &p_priv->var_lock );
404
405     if( p_this->psz_header ) free( p_this->psz_header );
406
407     if( p_this->i_object_type == VLC_OBJECT_GLOBAL )
408     {
409         libvlc_global_data_t *p_global = (libvlc_global_data_t *)p_this;
410         /* We are the global object ... no need to lock. */
411         free( p_global->pp_objects );
412         p_global->pp_objects = NULL;
413         p_global->i_objects--;
414
415         vlc_mutex_destroy( &structure_lock );
416     }
417     else
418     {
419         libvlc_global_data_t *p_libvlc_global = vlc_global();
420         int i_index;
421
422         vlc_mutex_lock( &structure_lock );
423
424         /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
425          * useless to try and recover anything if pp_objects gets smashed. */
426         i_index = FindIndex( p_this, p_libvlc_global->pp_objects,
427                              p_libvlc_global->i_objects );
428         REMOVE_ELEM( p_libvlc_global->pp_objects,
429                      p_libvlc_global->i_objects, i_index );
430
431         vlc_mutex_unlock( &structure_lock );
432     }
433
434 #if defined(WIN32) || defined(UNDER_CE)
435     /* if object has an associated thread, close it now */
436     if( p_priv->thread_id.hThread )
437        CloseHandle(p_priv->thread_id.hThread);
438 #endif
439
440     vlc_mutex_destroy( &p_this->object_lock );
441     vlc_cond_destroy( &p_this->object_wait );
442
443     /* global is not dynamically allocated by vlc_object_create */
444     if( p_this->i_object_type != VLC_OBJECT_GLOBAL )
445         free( p_priv );
446 }
447
448
449 void __vlc_object_kill( vlc_object_t *p_this )
450 {
451     vlc_mutex_lock( &p_this->object_lock );
452     p_this->b_die = VLC_TRUE;
453     vlc_mutex_unlock( &p_this->object_lock );
454 }
455
456
457 vlc_bool_t __vlc_object_dying_unlocked( vlc_object_t *p_this )
458 {
459     vlc_assert_locked( &p_this->object_lock );
460     return p_this->b_die;
461 }
462
463
464 vlc_bool_t __vlc_object_dying( vlc_object_t *p_this )
465 {
466      vlc_bool_t b;
467      vlc_mutex_lock( &p_this->object_lock );
468      b = __vlc_object_dying_unlocked( p_this );
469      vlc_mutex_unlock( &p_this->object_lock );
470      return b;
471 }
472
473
474 /**
475  * find an object given its ID
476  *
477  * This function looks for the object whose i_object_id field is i_id. We
478  * use a dichotomy so that lookups are in log2(n).
479  *****************************************************************************/
480 void * __vlc_object_get( vlc_object_t *p_this, int i_id )
481 {
482     int i_max, i_middle;
483     vlc_object_t **pp_objects;
484     libvlc_global_data_t *p_libvlc_global = vlc_global();
485
486     vlc_mutex_lock( &structure_lock );
487
488     pp_objects = p_libvlc_global->pp_objects;
489
490     /* Perform our dichotomy */
491     for( i_max = p_libvlc_global->i_objects - 1 ; ; )
492     {
493         i_middle = i_max / 2;
494
495         if( pp_objects[i_middle]->i_object_id > i_id )
496         {
497             i_max = i_middle;
498         }
499         else if( pp_objects[i_middle]->i_object_id < i_id )
500         {
501             if( i_middle )
502             {
503                 pp_objects += i_middle;
504                 i_max -= i_middle;
505             }
506             else
507             {
508                 /* This happens when there are only two remaining objects */
509                 if( pp_objects[i_middle+1]->i_object_id == i_id )
510                 {
511                     vlc_mutex_unlock( &structure_lock );
512                     pp_objects[i_middle+1]->i_refcount++;
513                     return pp_objects[i_middle+1];
514                 }
515                 break;
516             }
517         }
518         else
519         {
520             vlc_mutex_unlock( &structure_lock );
521             pp_objects[i_middle]->i_refcount++;
522             return pp_objects[i_middle];
523         }
524
525         if( i_max == 0 )
526         {
527             /* this means that i_max == i_middle, and since we have already
528              * tested pp_objects[i_middle]), p_found is properly set. */
529             break;
530         }
531     }
532
533     vlc_mutex_unlock( &structure_lock );
534     return NULL;
535 }
536
537 /**
538  ****************************************************************************
539  * find a typed object and increment its refcount
540  *****************************************************************************
541  * This function recursively looks for a given object type. i_mode can be one
542  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
543  *****************************************************************************/
544 void * __vlc_object_find( vlc_object_t *p_this, int i_type, int i_mode )
545 {
546     vlc_object_t *p_found;
547
548     vlc_mutex_lock( &structure_lock );
549
550     /* If we are of the requested type ourselves, don't look further */
551     if( !(i_mode & FIND_STRICT) && p_this->i_object_type == i_type )
552     {
553         p_this->i_refcount++;
554         vlc_mutex_unlock( &structure_lock );
555         return p_this;
556     }
557
558     /* Otherwise, recursively look for the object */
559     if( (i_mode & 0x000f) == FIND_ANYWHERE )
560     {
561         vlc_object_t *p_root = p_this;
562
563         /* Find the root */
564         while( p_root->p_parent != NULL &&
565                p_root != VLC_OBJECT( p_this->p_libvlc ) )
566         {
567             p_root = p_root->p_parent;
568         }
569
570         p_found = FindObject( p_root, i_type, (i_mode & ~0x000f)|FIND_CHILD );
571         if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_libvlc ) )
572         {
573             p_found = FindObject( VLC_OBJECT( p_this->p_libvlc ),
574                                   i_type, (i_mode & ~0x000f)|FIND_CHILD );
575         }
576     }
577     else
578     {
579         p_found = FindObject( p_this, i_type, i_mode );
580     }
581
582     vlc_mutex_unlock( &structure_lock );
583
584     return p_found;
585 }
586
587 /**
588  ****************************************************************************
589  * find a named object and increment its refcount
590  *****************************************************************************
591  * This function recursively looks for a given object name. i_mode can be one
592  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
593  *****************************************************************************/
594 void * __vlc_object_find_name( vlc_object_t *p_this, const char *psz_name,
595                                int i_mode )
596 {
597     vlc_object_t *p_found;
598
599     vlc_mutex_lock( &structure_lock );
600
601     /* If have the requested name ourselves, don't look further */
602     if( !(i_mode & FIND_STRICT)
603         && p_this->psz_object_name
604         && !strcmp( p_this->psz_object_name, psz_name ) )
605     {
606         p_this->i_refcount++;
607         vlc_mutex_unlock( &structure_lock );
608         return p_this;
609     }
610
611     /* Otherwise, recursively look for the object */
612     if( (i_mode & 0x000f) == FIND_ANYWHERE )
613     {
614         vlc_object_t *p_root = p_this;
615
616         /* Find the root */
617         while( p_root->p_parent != NULL &&
618                p_root != VLC_OBJECT( p_this->p_libvlc ) )
619         {
620             p_root = p_root->p_parent;
621         }
622
623         p_found = FindObjectName( p_root, psz_name,
624                                  (i_mode & ~0x000f)|FIND_CHILD );
625         if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_libvlc ) )
626         {
627             p_found = FindObjectName( VLC_OBJECT( p_this->p_libvlc ),
628                                       psz_name, (i_mode & ~0x000f)|FIND_CHILD );
629         }
630     }
631     else
632     {
633         p_found = FindObjectName( p_this, psz_name, i_mode );
634     }
635
636     vlc_mutex_unlock( &structure_lock );
637
638     return p_found;
639 }
640
641 /**
642  ****************************************************************************
643  * increment an object refcount
644  *****************************************************************************/
645 void __vlc_object_yield( vlc_object_t *p_this )
646 {
647     vlc_mutex_lock( &structure_lock );
648     p_this->i_refcount++;
649     vlc_mutex_unlock( &structure_lock );
650 }
651
652 /**
653  ****************************************************************************
654  * decrement an object refcount
655  *****************************************************************************/
656 void __vlc_object_release( vlc_object_t *p_this )
657 {
658     vlc_mutex_lock( &structure_lock );
659     p_this->i_refcount--;
660     vlc_mutex_unlock( &structure_lock );
661 }
662
663 /**
664  ****************************************************************************
665  * attach object to a parent object
666  *****************************************************************************
667  * This function sets p_this as a child of p_parent, and p_parent as a parent
668  * of p_this. This link can be undone using vlc_object_detach.
669  *****************************************************************************/
670 void __vlc_object_attach( vlc_object_t *p_this, vlc_object_t *p_parent )
671 {
672     if( !p_this ) return;
673
674     vlc_mutex_lock( &structure_lock );
675
676     /* Attach the parent to its child */
677     p_this->p_parent = p_parent;
678
679     /* Attach the child to its parent */
680     INSERT_ELEM( p_parent->pp_children, p_parent->i_children,
681                  p_parent->i_children, p_this );
682
683     /* Climb up the tree to see whether we are connected with the root */
684     if( p_parent->p_internals->b_attached )
685     {
686         SetAttachment( p_this, VLC_TRUE );
687     }
688
689     vlc_mutex_unlock( &structure_lock );
690 }
691
692 /**
693  ****************************************************************************
694  * detach object from its parent
695  *****************************************************************************
696  * This function removes all links between an object and its parent.
697  *****************************************************************************/
698 void __vlc_object_detach( vlc_object_t *p_this )
699 {
700     if( !p_this ) return;
701
702     vlc_mutex_lock( &structure_lock );
703     if( !p_this->p_parent )
704     {
705         msg_Err( p_this, "object is not attached" );
706         vlc_mutex_unlock( &structure_lock );
707         return;
708     }
709
710     /* Climb up the tree to see whether we are connected with the root */
711     if( p_this->p_parent->p_internals->b_attached )
712     {
713         SetAttachment( p_this, VLC_FALSE );
714     }
715
716     DetachObject( p_this );
717     vlc_mutex_unlock( &structure_lock );
718     p_this = NULL;
719 }
720
721 /**
722  ****************************************************************************
723  * find a list typed objects and increment their refcount
724  *****************************************************************************
725  * This function recursively looks for a given object type. i_mode can be one
726  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
727  *****************************************************************************/
728 vlc_list_t * __vlc_list_find( vlc_object_t *p_this, int i_type, int i_mode )
729 {
730     vlc_list_t *p_list;
731     vlc_object_t **pp_current, **pp_end;
732     int i_count = 0, i_index = 0;
733     libvlc_global_data_t *p_libvlc_global = vlc_global();
734
735     vlc_mutex_lock( &structure_lock );
736
737     /* Look for the objects */
738     switch( i_mode & 0x000f )
739     {
740     case FIND_ANYWHERE:
741         pp_current = p_libvlc_global->pp_objects;
742         pp_end = pp_current + p_libvlc_global->i_objects;
743
744         for( ; pp_current < pp_end ; pp_current++ )
745         {
746             if( (*pp_current)->p_internals->b_attached
747                  && (*pp_current)->i_object_type == i_type )
748             {
749                 i_count++;
750             }
751         }
752
753         p_list = NewList( i_count );
754         pp_current = p_libvlc_global->pp_objects;
755
756         for( ; pp_current < pp_end ; pp_current++ )
757         {
758             if( (*pp_current)->p_internals->b_attached
759                  && (*pp_current)->i_object_type == i_type )
760             {
761                 ListReplace( p_list, *pp_current, i_index );
762                 if( i_index < i_count ) i_index++;
763             }
764         }
765     break;
766
767     case FIND_CHILD:
768         i_count = CountChildren( p_this, i_type );
769         p_list = NewList( i_count );
770
771         /* Check allocation was successful */
772         if( p_list->i_count != i_count )
773         {
774             msg_Err( p_this, "list allocation failed!" );
775             p_list->i_count = 0;
776             break;
777         }
778
779         p_list->i_count = 0;
780         ListChildren( p_list, p_this, i_type );
781         break;
782
783     default:
784         msg_Err( p_this, "unimplemented!" );
785         p_list = NewList( 0 );
786         break;
787     }
788
789     vlc_mutex_unlock( &structure_lock );
790
791     return p_list;
792 }
793
794 /*****************************************************************************
795  * DumpCommand: print the current vlc structure
796  *****************************************************************************
797  * This function prints either an ASCII tree showing the connections between
798  * vlc objects, and additional information such as their refcount, thread ID,
799  * etc. (command "tree"), or the same data as a simple list (command "list").
800  *****************************************************************************/
801 static int DumpCommand( vlc_object_t *p_this, char const *psz_cmd,
802                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
803 {
804     libvlc_global_data_t *p_libvlc_global = vlc_global();
805
806     (void)oldval; (void)p_data;
807     if( *psz_cmd == 'l' )
808     {
809         vlc_mutex_lock( &structure_lock );
810
811         vlc_object_t **pp_current, **pp_end;
812
813         pp_current = p_libvlc_global->pp_objects;
814         pp_end = pp_current + p_libvlc_global->i_objects;
815
816         for( ; pp_current < pp_end ; pp_current++ )
817         {
818             if( (*pp_current)->p_internals->b_attached )
819             {
820                 PrintObject( *pp_current, "" );
821             }
822             else
823             {
824                 printf( " o %.8i %s (not attached)\n",
825                         (*pp_current)->i_object_id,
826                         (*pp_current)->psz_object_type );
827             }
828         }
829
830         vlc_mutex_unlock( &structure_lock );
831     }
832     else
833     {
834         vlc_object_t *p_object = NULL;
835
836         if( *newval.psz_string )
837         {
838             char *end;
839             int i_id = strtol( newval.psz_string, &end, 0 );
840             if( end != newval.psz_string )
841                 p_object = vlc_object_get( p_this, i_id );
842             else
843             {
844                 /* try using the object's name to find it */
845                 vlc_object_t *p_libvlc = vlc_object_get( p_this, 1 );
846                 if( p_libvlc )
847                 {
848                     /* Look in p_libvlc's children tree */
849                     p_object = vlc_object_find_name( p_libvlc,
850                                                      newval.psz_string,
851                                                      FIND_CHILD );
852                     vlc_object_release( p_libvlc );
853                 }
854                 if( !p_object )
855                 {
856                     /* If it's not in libvlc, look in libvlc_global (== p_this) */
857                     p_object = vlc_object_find_name( p_this,
858                                                      newval.psz_string,
859                                                      FIND_CHILD );
860                 }
861             }
862
863             if( !p_object )
864             {
865                 return VLC_ENOOBJ;
866             }
867         }
868
869         vlc_mutex_lock( &structure_lock );
870
871         if( *psz_cmd == 't' )
872         {
873             char psz_foo[2 * MAX_DUMPSTRUCTURE_DEPTH + 1];
874
875             if( !p_object )
876                 p_object = p_this->p_libvlc ? VLC_OBJECT(p_this->p_libvlc) : p_this;
877
878             psz_foo[0] = '|';
879             DumpStructure( p_object, 0, psz_foo );
880         }
881         else if( *psz_cmd == 'v' )
882         {
883             int i;
884
885             if( !p_object )
886                 p_object = p_this->p_libvlc ? VLC_OBJECT(p_this->p_libvlc) : p_this;
887
888             PrintObject( p_object, "" );
889
890             if( !p_object->p_internals->i_vars )
891                 printf( " `-o No variables\n" );
892             for( i = 0; i < p_object->p_internals->i_vars; i++ )
893             {
894                 variable_t *p_var = p_object->p_internals->p_vars + i;
895
896                 const char *psz_type = "unknown";
897                 switch( p_var->i_type & VLC_VAR_TYPE )
898                 {
899 #define MYCASE( type, nice )                \
900                     case VLC_VAR_ ## type:  \
901                         psz_type = nice;    \
902                         break;
903                     MYCASE( VOID, "void" );
904                     MYCASE( BOOL, "bool" );
905                     MYCASE( INTEGER, "integer" );
906                     MYCASE( HOTKEY, "hotkey" );
907                     MYCASE( STRING, "string" );
908                     MYCASE( MODULE, "module" );
909                     MYCASE( FILE, "file" );
910                     MYCASE( DIRECTORY, "directory" );
911                     MYCASE( VARIABLE, "variable" );
912                     MYCASE( FLOAT, "float" );
913                     MYCASE( TIME, "time" );
914                     MYCASE( ADDRESS, "address" );
915                     MYCASE( MUTEX, "mutex" );
916                     MYCASE( LIST, "list" );
917 #undef MYCASE
918                 }
919                 printf( " %c-o \"%s\" (%s",
920                         i + 1 == p_object->p_internals->i_vars ? '`' : '|',
921                         p_var->psz_name, psz_type );
922                 if( p_var->psz_text )
923                     printf( ", %s", p_var->psz_text );
924                 printf( ")" );
925                 if( p_var->i_type & VLC_VAR_ISCOMMAND )
926                     printf( ", command" );
927                 if( p_var->i_entries )
928                     printf( ", %d callbacks", p_var->i_entries );
929                 switch( p_var->i_type & 0x00f0 )
930                 {
931                     case VLC_VAR_VOID:
932                     case VLC_VAR_MUTEX:
933                         break;
934                     case VLC_VAR_BOOL:
935                         printf( ": %s", p_var->val.b_bool ? "true" : "false" );
936                         break;
937                     case VLC_VAR_INTEGER:
938                         printf( ": %d", p_var->val.i_int );
939                         break;
940                     case VLC_VAR_STRING:
941                         printf( ": \"%s\"", p_var->val.psz_string );
942                         break;
943                     case VLC_VAR_FLOAT:
944                         printf( ": %f", p_var->val.f_float );
945                         break;
946                     case VLC_VAR_TIME:
947                         printf( ": " I64Fi, (int64_t)p_var->val.i_time );
948                         break;
949                     case VLC_VAR_ADDRESS:
950                         printf( ": %p", p_var->val.p_address );
951                         break;
952                     case VLC_VAR_LIST:
953                         printf( ": TODO" );
954                         break;
955                 }
956                 printf( "\n" );
957             }
958         }
959
960         vlc_mutex_unlock( &structure_lock );
961
962         if( *newval.psz_string )
963         {
964             vlc_object_release( p_object );
965         }
966     }
967
968     return VLC_SUCCESS;
969 }
970
971 /*****************************************************************************
972  * vlc_list_release: free a list previously allocated by vlc_list_find
973  *****************************************************************************
974  * This function decreases the refcount of all objects in the list and
975  * frees the list.
976  *****************************************************************************/
977 void vlc_list_release( vlc_list_t *p_list )
978 {
979     int i_index;
980
981     vlc_mutex_lock( &structure_lock );
982     for( i_index = 0; i_index < p_list->i_count; i_index++ )
983     {
984         p_list->p_values[i_index].p_object->i_refcount--;
985     }
986     vlc_mutex_unlock( &structure_lock );
987
988     free( p_list->p_values );
989     free( p_list );
990 }
991
992 /* Following functions are local */
993
994 /*****************************************************************************
995  * FindIndex: find the index of an object in an array of objects
996  *****************************************************************************
997  * This function assumes that p_this can be found in pp_objects. It will not
998  * crash if p_this cannot be found, but will return a wrong value. It is your
999  * duty to check the return value if you are not certain that the object could
1000  * be found for sure.
1001  *****************************************************************************/
1002 static int FindIndex( vlc_object_t *p_this,
1003                       vlc_object_t **pp_objects, int i_count )
1004 {
1005     int i_middle = i_count / 2;
1006
1007     if( i_count == 0 )
1008     {
1009         return 0;
1010     }
1011
1012     if( pp_objects[i_middle] == p_this )
1013     {
1014         return i_middle;
1015     }
1016
1017     if( i_count == 1 )
1018     {
1019         return 0;
1020     }
1021
1022     /* We take advantage of the sorted array */
1023     if( pp_objects[i_middle]->i_object_id < p_this->i_object_id )
1024     {
1025         return i_middle + FindIndex( p_this, pp_objects + i_middle,
1026                                              i_count - i_middle );
1027     }
1028     else
1029     {
1030         return FindIndex( p_this, pp_objects, i_middle );
1031     }
1032 }
1033
1034 static vlc_object_t * FindObject( vlc_object_t *p_this, int i_type, int i_mode )
1035 {
1036     int i;
1037     vlc_object_t *p_tmp;
1038
1039     switch( i_mode & 0x000f )
1040     {
1041     case FIND_PARENT:
1042         p_tmp = p_this->p_parent;
1043         if( p_tmp )
1044         {
1045             if( p_tmp->i_object_type == i_type )
1046             {
1047                 p_tmp->i_refcount++;
1048                 return p_tmp;
1049             }
1050             else
1051             {
1052                 return FindObject( p_tmp, i_type, i_mode );
1053             }
1054         }
1055         break;
1056
1057     case FIND_CHILD:
1058         for( i = p_this->i_children; i--; )
1059         {
1060             p_tmp = p_this->pp_children[i];
1061             if( p_tmp->i_object_type == i_type )
1062             {
1063                 p_tmp->i_refcount++;
1064                 return p_tmp;
1065             }
1066             else if( p_tmp->i_children )
1067             {
1068                 p_tmp = FindObject( p_tmp, i_type, i_mode );
1069                 if( p_tmp )
1070                 {
1071                     return p_tmp;
1072                 }
1073             }
1074         }
1075         break;
1076
1077     case FIND_ANYWHERE:
1078         /* Handled in vlc_object_find */
1079         break;
1080     }
1081
1082     return NULL;
1083 }
1084
1085 static vlc_object_t * FindObjectName( vlc_object_t *p_this,
1086                                       const char *psz_name,
1087                                       int i_mode )
1088 {
1089     int i;
1090     vlc_object_t *p_tmp;
1091
1092     switch( i_mode & 0x000f )
1093     {
1094     case FIND_PARENT:
1095         p_tmp = p_this->p_parent;
1096         if( p_tmp )
1097         {
1098             if( p_tmp->psz_object_name
1099                 && !strcmp( p_tmp->psz_object_name, psz_name ) )
1100             {
1101                 p_tmp->i_refcount++;
1102                 return p_tmp;
1103             }
1104             else
1105             {
1106                 return FindObjectName( p_tmp, psz_name, i_mode );
1107             }
1108         }
1109         break;
1110
1111     case FIND_CHILD:
1112         for( i = p_this->i_children; i--; )
1113         {
1114             p_tmp = p_this->pp_children[i];
1115             if( p_tmp->psz_object_name
1116                 && !strcmp( p_tmp->psz_object_name, psz_name ) )
1117             {
1118                 p_tmp->i_refcount++;
1119                 return p_tmp;
1120             }
1121             else if( p_tmp->i_children )
1122             {
1123                 p_tmp = FindObjectName( p_tmp, psz_name, i_mode );
1124                 if( p_tmp )
1125                 {
1126                     return p_tmp;
1127                 }
1128             }
1129         }
1130         break;
1131
1132     case FIND_ANYWHERE:
1133         /* Handled in vlc_object_find */
1134         break;
1135     }
1136
1137     return NULL;
1138 }
1139
1140 static void DetachObject( vlc_object_t *p_this )
1141 {
1142     vlc_object_t *p_parent = p_this->p_parent;
1143     int i_index, i;
1144
1145     /* Remove p_this's parent */
1146     p_this->p_parent = NULL;
1147
1148     /* Remove all of p_parent's children which are p_this */
1149     for( i_index = p_parent->i_children ; i_index-- ; )
1150     {
1151         if( p_parent->pp_children[i_index] == p_this )
1152         {
1153             p_parent->i_children--;
1154             for( i = i_index ; i < p_parent->i_children ; i++ )
1155             {
1156                 p_parent->pp_children[i] = p_parent->pp_children[i+1];
1157             }
1158         }
1159     }
1160
1161     if( p_parent->i_children )
1162     {
1163         p_parent->pp_children = (vlc_object_t **)realloc( p_parent->pp_children,
1164                                p_parent->i_children * sizeof(vlc_object_t *) );
1165     }
1166     else
1167     {
1168         free( p_parent->pp_children );
1169         p_parent->pp_children = NULL;
1170     }
1171 }
1172
1173 /*****************************************************************************
1174  * SetAttachment: recursively set the b_attached flag of a subtree.
1175  *****************************************************************************
1176  * This function is used by the attach and detach functions to propagate
1177  * the b_attached flag in a subtree.
1178  *****************************************************************************/
1179 static void SetAttachment( vlc_object_t *p_this, vlc_bool_t b_attached )
1180 {
1181     int i_index;
1182
1183     for( i_index = p_this->i_children ; i_index-- ; )
1184     {
1185         SetAttachment( p_this->pp_children[i_index], b_attached );
1186     }
1187
1188     p_this->p_internals->b_attached = b_attached;
1189 }
1190
1191 static void PrintObject( vlc_object_t *p_this, const char *psz_prefix )
1192 {
1193     char psz_children[20], psz_refcount[20], psz_thread[30], psz_name[50],
1194          psz_parent[20];
1195
1196     psz_name[0] = '\0';
1197     if( p_this->psz_object_name )
1198     {
1199         snprintf( psz_name, 49, " \"%s\"", p_this->psz_object_name );
1200         if( psz_name[48] )
1201             psz_name[48] = '\"';
1202     }
1203
1204     psz_children[0] = '\0';
1205     switch( p_this->i_children )
1206     {
1207         case 0:
1208             break;
1209         case 1:
1210             strcpy( psz_children, ", 1 child" );
1211             break;
1212         default:
1213             snprintf( psz_children, 19, ", %i children", p_this->i_children );
1214             break;
1215     }
1216
1217     psz_refcount[0] = '\0';
1218     if( p_this->i_refcount )
1219         snprintf( psz_refcount, 19, ", refcount %i", p_this->i_refcount );
1220
1221     psz_thread[0] = '\0';
1222     if( p_this->p_internals->b_thread )
1223         snprintf( psz_thread, 29, " (thread %u)",
1224 #if defined(WIN32) || defined(UNDER_CE)
1225                   (unsigned)p_this->p_internals->thread_id.id );
1226 #else
1227                   (unsigned)p_this->p_internals->thread_id );
1228 #endif
1229
1230     psz_parent[0] = '\0';
1231     if( p_this->p_parent )
1232         snprintf( psz_parent, 19, ", parent %i", p_this->p_parent->i_object_id );
1233
1234     printf( " %so %.8i %s%s%s%s%s%s\n", psz_prefix,
1235             p_this->i_object_id, p_this->psz_object_type,
1236             psz_name, psz_thread, psz_refcount, psz_children,
1237             psz_parent );
1238 }
1239
1240 static void DumpStructure( vlc_object_t *p_this, int i_level, char *psz_foo )
1241 {
1242     int i;
1243     char i_back = psz_foo[i_level];
1244     psz_foo[i_level] = '\0';
1245
1246     PrintObject( p_this, psz_foo );
1247
1248     psz_foo[i_level] = i_back;
1249
1250     if( i_level / 2 >= MAX_DUMPSTRUCTURE_DEPTH )
1251     {
1252         msg_Warn( p_this, "structure tree is too deep" );
1253         return;
1254     }
1255
1256     for( i = 0 ; i < p_this->i_children ; i++ )
1257     {
1258         if( i_level )
1259         {
1260             psz_foo[i_level-1] = ' ';
1261
1262             if( psz_foo[i_level-2] == '`' )
1263             {
1264                 psz_foo[i_level-2] = ' ';
1265             }
1266         }
1267
1268         if( i == p_this->i_children - 1 )
1269         {
1270             psz_foo[i_level] = '`';
1271         }
1272         else
1273         {
1274             psz_foo[i_level] = '|';
1275         }
1276
1277         psz_foo[i_level+1] = '-';
1278         psz_foo[i_level+2] = '\0';
1279
1280         DumpStructure( p_this->pp_children[i], i_level + 2, psz_foo );
1281     }
1282 }
1283
1284 static vlc_list_t * NewList( int i_count )
1285 {
1286     vlc_list_t * p_list = (vlc_list_t *)malloc( sizeof( vlc_list_t ) );
1287     if( p_list == NULL )
1288     {
1289         return NULL;
1290     }
1291
1292     p_list->i_count = i_count;
1293
1294     if( i_count == 0 )
1295     {
1296         p_list->p_values = NULL;
1297         return p_list;
1298     }
1299
1300     p_list->p_values = malloc( i_count * sizeof( vlc_value_t ) );
1301     if( p_list->p_values == NULL )
1302     {
1303         p_list->i_count = 0;
1304         return p_list;
1305     }
1306
1307     return p_list;
1308 }
1309
1310 static void ListReplace( vlc_list_t *p_list, vlc_object_t *p_object,
1311                          int i_index )
1312 {
1313     if( p_list == NULL || i_index >= p_list->i_count )
1314     {
1315         return;
1316     }
1317
1318     p_object->i_refcount++;
1319
1320     p_list->p_values[i_index].p_object = p_object;
1321
1322     return;
1323 }
1324
1325 /*static void ListAppend( vlc_list_t *p_list, vlc_object_t *p_object )
1326 {
1327     if( p_list == NULL )
1328     {
1329         return;
1330     }
1331
1332     p_list->p_values = realloc( p_list->p_values, (p_list->i_count + 1)
1333                                 * sizeof( vlc_value_t ) );
1334     if( p_list->p_values == NULL )
1335     {
1336         p_list->i_count = 0;
1337         return;
1338     }
1339
1340     p_object->i_refcount++;
1341
1342     p_list->p_values[p_list->i_count].p_object = p_object;
1343     p_list->i_count++;
1344
1345     return;
1346 }*/
1347
1348 static int CountChildren( vlc_object_t *p_this, int i_type )
1349 {
1350     vlc_object_t *p_tmp;
1351     int i, i_count = 0;
1352
1353     for( i = 0; i < p_this->i_children; i++ )
1354     {
1355         p_tmp = p_this->pp_children[i];
1356
1357         if( p_tmp->i_object_type == i_type )
1358         {
1359             i_count++;
1360         }
1361
1362         if( p_tmp->i_children )
1363         {
1364             i_count += CountChildren( p_tmp, i_type );
1365         }
1366     }
1367
1368     return i_count;
1369 }
1370
1371 static void ListChildren( vlc_list_t *p_list, vlc_object_t *p_this, int i_type )
1372 {
1373     vlc_object_t *p_tmp;
1374     int i;
1375
1376     for( i = 0; i < p_this->i_children; i++ )
1377     {
1378         p_tmp = p_this->pp_children[i];
1379
1380         if( p_tmp->i_object_type == i_type )
1381         {
1382             ListReplace( p_list, p_tmp, p_list->i_count++ );
1383         }
1384
1385         if( p_tmp->i_children )
1386         {
1387             ListChildren( p_list, p_tmp, i_type );
1388         }
1389     }
1390 }