]> git.sesse.net Git - vlc/blob - src/misc/objects.c
Remove XML object type
[vlc] / src / misc / objects.c
1 /*****************************************************************************
2  * objects.c: vlc_object_t handling
3  *****************************************************************************
4  * Copyright (C) 2004-2008 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 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36
37 #include <vlc/vlc.h>
38
39 #include "../libvlc.h"
40 #include <vlc_vout.h>
41 #include <vlc_aout.h>
42 #include "audio_output/aout_internal.h"
43
44 #include <vlc_access.h>
45 #include <vlc_demux.h>
46 #include <vlc_stream.h>
47
48 #include <vlc_sout.h>
49 #include "stream_output/stream_output.h"
50
51 #include "vlc_playlist.h"
52 #include "vlc_interface.h"
53 #include "vlc_codec.h"
54 #include "vlc_filter.h"
55
56 #include "vlc_httpd.h"
57 #include "vlc_vlm.h"
58 #include "input/vlm_internal.h"
59 #include "vlc_osd.h"
60 #include "vlc_meta.h"
61
62 #include "variables.h"
63 #ifndef WIN32
64 # include <unistd.h>
65 #else
66 # include <io.h>
67 # include <fcntl.h>
68 # include <errno.h> /* ENOSYS */
69 #endif
70 #include <assert.h>
71
72 /*****************************************************************************
73  * Constants
74  *****************************************************************************/
75
76 const vlc_destructor_t kVLCDestructor = NULL;
77
78 /*****************************************************************************
79  * Local prototypes
80  *****************************************************************************/
81 static int  DumpCommand( vlc_object_t *, char const *,
82                          vlc_value_t, vlc_value_t, void * );
83
84 static vlc_object_t * FindObject    ( vlc_object_t *, int, int );
85 static vlc_object_t * FindObjectName( vlc_object_t *, const char *, int );
86 static void           DetachObject  ( vlc_object_t * );
87 static void           PrintObject   ( vlc_object_t *, const char * );
88 static void           DumpStructure ( vlc_object_t *, int, char * );
89 static int            FindIndex     ( vlc_object_t *, vlc_object_t **, int );
90 static void           SetAttachment ( vlc_object_t *, vlc_bool_t );
91
92 static vlc_list_t   * NewList       ( int );
93 static void           ListReplace   ( vlc_list_t *, vlc_object_t *, int );
94 /*static void           ListAppend    ( vlc_list_t *, vlc_object_t * );*/
95 static int            CountChildren ( vlc_object_t *, int );
96 static void           ListChildren  ( vlc_list_t *, vlc_object_t *, int );
97
98 static void vlc_object_destroy( vlc_object_t *p_this );
99 static void vlc_object_yield_locked( vlc_object_t *p_this );
100
101 /*****************************************************************************
102  * Local structure lock
103  *****************************************************************************/
104 static vlc_mutex_t    structure_lock;
105 static vlc_object_internals_t global_internals;
106
107 vlc_object_t *vlc_custom_create( vlc_object_t *p_this, size_t i_size,
108                                  int i_type, const char *psz_type )
109 {
110     vlc_object_t *p_new;
111     vlc_object_internals_t *p_priv;
112
113     if( i_type == VLC_OBJECT_GLOBAL )
114     {
115         p_new = p_this;
116         p_priv = &global_internals;
117         memset( p_priv, 0, sizeof( *p_priv ) );
118     }
119     else
120     {
121         p_priv = calloc( 1, sizeof( *p_priv ) + i_size );
122         if( p_priv == NULL )
123             return NULL;
124
125         p_new = (vlc_object_t *)(p_priv + 1);
126     }
127
128     p_new->p_internals = p_priv;
129     p_new->i_object_type = i_type;
130     p_new->psz_object_type = psz_type;
131
132     p_new->psz_object_name = NULL;
133
134     p_new->b_die = VLC_FALSE;
135     p_new->b_error = VLC_FALSE;
136     p_new->b_dead = VLC_FALSE;
137     p_priv->b_attached = VLC_FALSE;
138     p_new->b_force = VLC_FALSE;
139
140     p_new->psz_header = NULL;
141
142     if( p_this->i_flags & OBJECT_FLAGS_NODBG )
143         p_new->i_flags |= OBJECT_FLAGS_NODBG;
144     if( p_this->i_flags & OBJECT_FLAGS_QUIET )
145         p_new->i_flags |= OBJECT_FLAGS_QUIET;
146     if( p_this->i_flags & OBJECT_FLAGS_NOINTERACT )
147         p_new->i_flags |= OBJECT_FLAGS_NOINTERACT;
148
149     p_priv->p_vars = calloc( sizeof( variable_t ), 16 );
150
151     if( !p_priv->p_vars )
152     {
153         if( i_type != VLC_OBJECT_GLOBAL )
154             free( p_priv );
155         return NULL;
156     }
157
158     if( i_type == VLC_OBJECT_GLOBAL )
159     {
160         /* If i_type is global, then p_new is actually p_libvlc_global */
161         libvlc_global_data_t *p_libvlc_global = (libvlc_global_data_t *)p_new;
162         p_new->p_libvlc = NULL;
163
164         p_libvlc_global->i_counter = 0;
165         p_new->i_object_id = 0;
166
167         p_libvlc_global->i_objects = 1;
168         p_libvlc_global->pp_objects = malloc( sizeof(vlc_object_t *) );
169         p_libvlc_global->pp_objects[0] = p_new;
170         p_priv->b_attached = VLC_TRUE;
171     }
172     else
173     {
174         libvlc_global_data_t *p_libvlc_global = vlc_global();
175         if( i_type == VLC_OBJECT_LIBVLC )
176         {
177             p_new->p_libvlc = (libvlc_int_t*)p_new;
178             p_priv->b_attached = VLC_TRUE;
179         }
180         else
181         {
182             p_new->p_libvlc = p_this->p_libvlc;
183         }
184
185         vlc_mutex_lock( &structure_lock );
186
187         p_libvlc_global->i_counter++;
188         p_new->i_object_id = p_libvlc_global->i_counter;
189
190         /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
191          * useless to try and recover anything if pp_objects gets smashed. */
192         TAB_APPEND( p_libvlc_global->i_objects, p_libvlc_global->pp_objects,
193                     p_new );
194
195         vlc_mutex_unlock( &structure_lock );
196     }
197
198     p_priv->i_refcount = 1;
199     p_priv->pf_destructor = kVLCDestructor;
200     p_priv->b_thread = VLC_FALSE;
201     p_new->p_parent = NULL;
202     p_new->pp_children = NULL;
203     p_new->i_children = 0;
204
205     p_new->p_private = NULL;
206
207     /* Initialize mutexes and condvars */
208     vlc_mutex_init( p_new, &p_new->object_lock );
209     vlc_cond_init( p_new, &p_new->object_wait );
210     vlc_mutex_init( p_new, &p_priv->var_lock );
211     vlc_spin_init( &p_priv->spin );
212     p_priv->pipes[0] = p_priv->pipes[1] = -1;
213
214     if( i_type == VLC_OBJECT_GLOBAL )
215     {
216         vlc_mutex_init( p_new, &structure_lock );
217     }
218
219     if( i_type == VLC_OBJECT_LIBVLC )
220     {
221         var_Create( p_new, "list", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
222         var_AddCallback( p_new, "list", DumpCommand, NULL );
223         var_Create( p_new, "tree", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
224         var_AddCallback( p_new, "tree", DumpCommand, NULL );
225         var_Create( p_new, "vars", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
226         var_AddCallback( p_new, "vars", DumpCommand, NULL );
227     }
228
229     return p_new;
230 }
231
232
233 /**
234  * Allocates and initializes a vlc object.
235  *
236  * @param i_type known object type (all of them are negative integer values),
237  *               or object byte size (always positive).
238  *
239  * @return the new object, or NULL on error.
240  */
241 void * __vlc_object_create( vlc_object_t *p_this, int i_type )
242 {
243     const char   * psz_type;
244     size_t         i_size;
245
246     switch( i_type )
247     {
248         case VLC_OBJECT_GLOBAL:
249             i_size = sizeof(libvlc_global_data_t);
250             psz_type = "global";
251             break;
252         case VLC_OBJECT_LIBVLC:
253             i_size = sizeof(libvlc_int_t);
254             psz_type = "libvlc";
255             break;
256         case VLC_OBJECT_INTF:
257             i_size = sizeof(intf_thread_t);
258             psz_type = "interface";
259             break;
260         case VLC_OBJECT_DIALOGS:
261             i_size = sizeof(intf_thread_t);
262             psz_type = "dialogs";
263             break;
264         case VLC_OBJECT_PLAYLIST:
265             i_size = sizeof(playlist_t);
266             psz_type = "playlist";
267             break;
268         case VLC_OBJECT_INPUT:
269             i_size = sizeof(input_thread_t);
270             psz_type = "input";
271             break;
272         case VLC_OBJECT_DEMUX:
273             i_size = sizeof(demux_t);
274             psz_type = "demux";
275             break;
276         case VLC_OBJECT_ACCESS:
277             i_size = sizeof(access_t);
278             psz_type = "access";
279             break;
280         case VLC_OBJECT_DECODER:
281             i_size = sizeof(decoder_t);
282             psz_type = "decoder";
283             break;
284         case VLC_OBJECT_PACKETIZER:
285             i_size = sizeof(decoder_t);
286             psz_type = "packetizer";
287             break;
288         case VLC_OBJECT_ENCODER:
289             i_size = sizeof(encoder_t);
290             psz_type = "encoder";
291             break;
292         case VLC_OBJECT_FILTER:
293             i_size = sizeof(filter_t);
294             psz_type = "filter";
295             break;
296         case VLC_OBJECT_VOUT:
297             i_size = sizeof(vout_thread_t);
298             psz_type = "video output";
299             break;
300         case VLC_OBJECT_AOUT:
301             i_size = sizeof(aout_instance_t);
302             psz_type = "audio output";
303             break;
304         case VLC_OBJECT_SOUT:
305             i_size = sizeof(sout_instance_t);
306             psz_type = "stream output";
307             break;
308         case VLC_OBJECT_VLM:
309             i_size = sizeof( vlm_t );
310             psz_type = "vlm dameon";
311             break;
312         case VLC_OBJECT_OPENGL:
313             i_size = sizeof( vout_thread_t );
314             psz_type = "opengl";
315             break;
316         case VLC_OBJECT_ANNOUNCE:
317             i_size = sizeof( announce_handler_t );
318             psz_type = "announce";
319             break;
320         case VLC_OBJECT_META_ENGINE:
321             i_size = sizeof( meta_engine_t );
322             psz_type = "meta engine";
323             break;
324         case VLC_OBJECT_OSDMENU:
325             i_size = sizeof( osd_menu_t );
326             psz_type = "osd menu";
327             break;
328         case VLC_OBJECT_INTERACTION:
329             i_size = sizeof( interaction_t );
330             psz_type = "interaction";
331             break;
332         default:
333             i_size = i_type > (int)sizeof(vlc_object_t)
334                          ? i_type : (int)sizeof(vlc_object_t);
335             i_type = VLC_OBJECT_GENERIC;
336             psz_type = "generic";
337             break;
338     }
339
340     return vlc_custom_create( p_this, i_size, i_type, psz_type );
341 }
342
343
344 /**
345  ****************************************************************************
346  * Set the destructor of a vlc object
347  *
348  * This function sets the destructor of the vlc object. It will be called
349  * when the object is destroyed when the its refcount reaches 0.
350  * (It is called by the internal function vlc_object_destroy())
351  *****************************************************************************/
352 void __vlc_object_set_destructor( vlc_object_t *p_this,
353                                   vlc_destructor_t pf_destructor )
354 {
355     vlc_object_internals_t *p_priv = vlc_internals(p_this );
356
357     vlc_mutex_lock( &structure_lock );
358     p_priv->pf_destructor = pf_destructor;
359     vlc_mutex_unlock( &structure_lock );
360 }
361
362 /**
363  ****************************************************************************
364  * Destroy a vlc object (Internal)
365  *
366  * This function destroys an object that has been previously allocated with
367  * vlc_object_create. The object's refcount must be zero and it must not be
368  * attached to other objects in any way.
369  *****************************************************************************/
370 static void vlc_object_destroy( vlc_object_t *p_this )
371 {
372     vlc_object_internals_t *p_priv = vlc_internals( p_this );
373
374     /* Automatically detach the object from its parents */
375     if( p_this->p_parent ) vlc_object_detach( p_this );
376
377
378     /* Send a kill to the object's thread if applicable */
379     vlc_object_kill( p_this );
380
381     /* If we are running on a thread, wait until it ends */
382     if( p_priv->b_thread )
383         vlc_thread_join( p_this );
384
385     /* Call the custom "subclass" destructor */
386     if( p_priv->pf_destructor )
387         p_priv->pf_destructor( p_this );
388
389     /* Sanity checks */
390     if( p_this->i_children )
391     {
392         int i;
393
394         fprintf( stderr,
395                  "ERROR: cannot delete object (%i, %s) with %d children\n",
396                  p_this->i_object_id, p_this->psz_object_name,
397                  p_this->i_children );
398
399         for( i = 0; i < p_this->i_children; i++ )
400         {
401             fprintf( stderr,
402                      "ERROR: Remaining children object "
403                      "(id:%i, type:%s, name:%s)\n",
404                      p_this->pp_children[i]->i_object_id,
405                      p_this->pp_children[i]->psz_object_type,
406                      p_this->pp_children[i]->psz_object_name );
407         }
408         fflush(stderr);
409         abort();
410     }
411
412     /* Destroy the associated variables, starting from the end so that
413      * no memmove calls have to be done. */
414     while( p_priv->i_vars )
415     {
416         var_Destroy( p_this, p_priv->p_vars[p_priv->i_vars - 1].psz_name );
417     }
418
419     free( p_priv->p_vars );
420     vlc_mutex_destroy( &p_priv->var_lock );
421
422     free( p_this->psz_header );
423
424     if( p_this->i_object_type == VLC_OBJECT_GLOBAL )
425     {
426         libvlc_global_data_t *p_global = (libvlc_global_data_t *)p_this;
427
428         /* Test for leaks */
429         if( p_global->i_objects > 0 )
430         {
431             int i;
432             for( i = 0; i < p_global->i_objects; i++ )
433             {
434                 /* We are leaking this object */
435                 fprintf( stderr,
436                          "ERROR: leaking object (id:%i, type:%s, name:%s)\n",
437                          p_global->pp_objects[i]->i_object_id,
438                          p_global->pp_objects[i]->psz_object_type,
439                          p_global->pp_objects[i]->psz_object_name );
440                 fflush(stderr);
441             }
442             /* Strongly abort, cause we want these to be fixed */
443             abort();
444         }
445
446         /* We are the global object ... no need to lock. */
447         free( p_global->pp_objects );
448         p_global->pp_objects = NULL;
449
450         vlc_mutex_destroy( &structure_lock );
451     }
452
453 #if defined(WIN32) || defined(UNDER_CE)
454     /* if object has an associated thread, close it now */
455     if( p_priv->thread_id.hThread )
456        CloseHandle(p_priv->thread_id.hThread);
457 #endif
458
459     vlc_mutex_destroy( &p_this->object_lock );
460     vlc_cond_destroy( &p_this->object_wait );
461     vlc_spin_destroy( &p_priv->spin );
462     if( p_priv->pipes[1] != -1 )
463         close( p_priv->pipes[1] );
464     if( p_priv->pipes[0] != -1 )
465         close( p_priv->pipes[0] );
466
467     /* global is not dynamically allocated by vlc_object_create */
468     if( p_this->i_object_type != VLC_OBJECT_GLOBAL )
469         free( p_priv );
470 }
471
472
473 /** Inter-object signaling */
474
475 void __vlc_object_lock( vlc_object_t *obj )
476 {
477     vlc_mutex_lock( &obj->object_lock );
478 }
479
480 void __vlc_object_unlock( vlc_object_t *obj )
481 {
482     vlc_assert_locked( &obj->object_lock );
483     vlc_mutex_unlock( &obj->object_lock );
484 }
485
486 #ifdef WIN32
487 # include <winsock2.h>
488 # include <ws2tcpip.h>
489
490 /**
491  * select()-able pipes emulated using Winsock
492  */
493 static int pipe (int fd[2])
494 {
495     SOCKADDR_IN addr;
496     int addrlen = sizeof (addr);
497
498     SOCKET l = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP), a,
499            c = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
500     if ((l == INVALID_SOCKET) || (c == INVALID_SOCKET))
501         goto error;
502
503     memset (&addr, 0, sizeof (addr));
504     addr.sin_family = AF_INET;
505     addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
506     if (bind (l, (PSOCKADDR)&addr, sizeof (addr))
507      || getsockname (l, (PSOCKADDR)&addr, &addrlen)
508      || listen (l, 1)
509      || connect (c, (PSOCKADDR)&addr, addrlen))
510         goto error;
511
512     a = accept (l, NULL, NULL);
513     if (a == INVALID_SOCKET)
514         goto error;
515
516     closesocket (l);
517     //shutdown (a, 0);
518     //shutdown (c, 1);
519     fd[0] = c;
520     fd[1] = a;
521     return 0;
522
523 error:
524     if (l != INVALID_SOCKET)
525         closesocket (l);
526     if (c != INVALID_SOCKET)
527         closesocket (c);
528     return -1;
529 }
530
531 #undef  read
532 #define read( a, b, c )  recv (a, b, c, 0)
533 #undef  write
534 #define write( a, b, c ) send (a, b, c, 0)
535 #undef  close
536 #define close( a )       closesocket (a)
537 #endif /* WIN32 */
538
539 /**
540  * Returns the readable end of a pipe that becomes readable once termination
541  * of the object is requested (vlc_object_kill()).
542  * This can be used to wake-up out of a select() or poll() event loop, such
543  * typically when doing network I/O.
544  *
545  * Note that the pipe will remain the same for the lifetime of the object.
546  * DO NOT read the pipe nor close it yourself. Ever.
547  *
548  * @param obj object that would be "killed"
549  * @return a readable pipe descriptor, or -1 on error.
550  */
551 int __vlc_object_waitpipe( vlc_object_t *obj )
552 {
553     int pfd[2] = { -1, -1 };
554     struct vlc_object_internals_t *internals = obj->p_internals;
555     vlc_bool_t killed = VLC_FALSE;
556
557     vlc_spin_lock (&internals->spin);
558     if (internals->pipes[0] == -1)
559     {
560         /* This can only ever happen if someone killed us without locking: */
561         assert (internals->pipes[1] == -1);
562         vlc_spin_unlock (&internals->spin);
563
564         if (pipe (pfd))
565             return -1;
566
567         vlc_spin_lock (&internals->spin);
568         if (internals->pipes[0] == -1)
569         {
570             internals->pipes[0] = pfd[0];
571             internals->pipes[1] = pfd[1];
572             pfd[0] = pfd[1] = -1;
573         }
574         killed = obj->b_die;
575     }
576     vlc_spin_unlock (&internals->spin);
577
578     if (killed)
579     {
580         /* Race condition: vlc_object_kill() already invoked! */
581         int fd;
582
583         vlc_spin_lock (&internals->spin);
584         fd = internals->pipes[1];
585         internals->pipes[1] = -1;
586         vlc_spin_unlock (&internals->spin);
587
588         msg_Dbg (obj, "waitpipe: object already dying");
589         if (fd != -1)
590             close (fd);
591     }
592
593     /* Race condition: two threads call pipe() - unlikely */
594     if (pfd[0] != -1)
595         close (pfd[0]);
596     if (pfd[1] != -1)
597         close (pfd[1]);
598
599     return internals->pipes[0];
600 }
601
602
603 /**
604  * Waits for the object to be signaled (using vlc_object_signal()).
605  * If the object already has a signal pending, this function will return
606  * immediately. It is asserted that the caller holds the object lock.
607  *
608  * @return true if the object is dying and should terminate.
609  */
610 vlc_bool_t __vlc_object_wait( vlc_object_t *obj )
611 {
612     vlc_assert_locked( &obj->object_lock );
613     vlc_cond_wait( &obj->object_wait, &obj->object_lock );
614     return obj->b_die;
615 }
616
617
618 /**
619  * Waits for the object to be signaled (using vlc_object_signal()), or for
620  * a timer to expire.
621  * If the object already has a signal pending, this function will return
622  * immediately. It is asserted that the caller holds the object lock.
623  *
624  * @return negative if the object is dying and should terminate,
625  * positive if the the object has been signaled but is not dying,
626  * 0 if timeout has been reached.
627  */
628 int __vlc_object_timedwait( vlc_object_t *obj, mtime_t deadline )
629 {
630     int v;
631
632     vlc_assert_locked( &obj->object_lock );
633     v = vlc_cond_timedwait( &obj->object_wait, &obj->object_lock, deadline );
634     if( v == 0 ) /* signaled */
635         return obj->b_die ? -1 : 1;
636     return 0;
637 }
638
639
640 /**
641  * Checks whether an object has been "killed".
642  * The object lock must be held.
643  *
644  * Typical code for an object thread could be:
645  *
646    vlc_object_lock (self);
647    ...initialization...
648    while (vlc_object_alive (self))
649    {
650        ...preprocessing...
651
652        if (vlc_object_wait (self))
653            continue;
654
655        ...postprocessing...
656    }
657    ...deinitialization...
658    vlc_object_unlock (self);
659  *
660  *
661  * @return true iff the object has not been killed yet
662  */
663 vlc_bool_t __vlc_object_alive( vlc_object_t *obj )
664 {
665     vlc_assert_locked( &obj->object_lock );
666     return !obj->b_die;
667 }
668
669
670 /**
671  * Signals an object for which the lock is held.
672  */
673 void __vlc_object_signal_unlocked( vlc_object_t *obj )
674 {
675     vlc_assert_locked (&obj->object_lock);
676     vlc_cond_signal( &obj->object_wait );
677 }
678
679
680 /**
681  * Requests termination of an object.
682  * If the object is LibVLC, also request to terminate all its children.
683  */
684 void __vlc_object_kill( vlc_object_t *p_this )
685 {
686     struct vlc_object_internals_t *internals = p_this->p_internals;
687     int fd;
688
689     vlc_mutex_lock( &p_this->object_lock );
690     p_this->b_die = VLC_TRUE;
691
692     vlc_spin_lock (&internals->spin);
693     fd = internals->pipes[1];
694     internals->pipes[1] = -1;
695     vlc_spin_unlock (&internals->spin);
696
697     if( fd != -1 )
698     {
699         msg_Dbg (p_this, "waitpipe: object killed");
700         close (fd);
701     }
702
703     if( p_this->i_object_type == VLC_OBJECT_LIBVLC )
704         for( int i = 0; i < p_this->i_children ; i++ )
705             vlc_object_kill( p_this->pp_children[i] );
706
707     vlc_object_signal_unlocked( p_this );
708     vlc_mutex_unlock( &p_this->object_lock );
709 }
710
711
712 /**
713  * find an object given its ID
714  *
715  * This function looks for the object whose i_object_id field is i_id. We
716  * use a dichotomy so that lookups are in log2(n).
717  *****************************************************************************/
718 void * vlc_object_get( int i_id )
719 {
720     int i_max, i_middle;
721     vlc_object_t **pp_objects;
722     libvlc_global_data_t *p_libvlc_global = vlc_global();
723
724     vlc_mutex_lock( &structure_lock );
725
726     pp_objects = p_libvlc_global->pp_objects;
727
728     /* Perform our dichotomy */
729     for( i_max = p_libvlc_global->i_objects - 1 ; ; )
730     {
731         i_middle = i_max / 2;
732
733         if( pp_objects[i_middle]->i_object_id > i_id )
734         {
735             i_max = i_middle;
736         }
737         else if( pp_objects[i_middle]->i_object_id < i_id )
738         {
739             if( i_middle )
740             {
741                 pp_objects += i_middle;
742                 i_max -= i_middle;
743             }
744             else
745             {
746                 /* This happens when there are only two remaining objects */
747                 if( pp_objects[i_middle+1]->i_object_id == i_id
748                     && pp_objects[i_middle+1]->p_internals->i_refcount > 0 )
749                 {
750                     vlc_object_yield_locked( pp_objects[i_middle+1] );
751                     vlc_mutex_unlock( &structure_lock );
752                     return pp_objects[i_middle+1];
753                 }
754                 break;
755             }
756         }
757         else if( pp_objects[i_middle]->p_internals->i_refcount > 0 )
758         {
759             vlc_object_yield_locked( pp_objects[i_middle] );
760             vlc_mutex_unlock( &structure_lock );
761             return pp_objects[i_middle];
762         }
763
764         if( i_max == 0 )
765         {
766             /* this means that i_max == i_middle, and since we have already
767              * tested pp_objects[i_middle]), p_found is properly set. */
768             break;
769         }
770     }
771
772     vlc_mutex_unlock( &structure_lock );
773     return NULL;
774 }
775
776 /**
777  ****************************************************************************
778  * find a typed object and increment its refcount
779  *****************************************************************************
780  * This function recursively looks for a given object type. i_mode can be one
781  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
782  *****************************************************************************/
783 void * __vlc_object_find( vlc_object_t *p_this, int i_type, int i_mode )
784 {
785     vlc_object_t *p_found;
786
787     vlc_mutex_lock( &structure_lock );
788
789     /* If we are of the requested type ourselves, don't look further */
790     if( !(i_mode & FIND_STRICT) && p_this->i_object_type == i_type
791         && p_this->p_internals->i_refcount > 0 )
792     {
793         vlc_object_yield_locked( p_this );
794         vlc_mutex_unlock( &structure_lock );
795         return p_this;
796     }
797
798     /* Otherwise, recursively look for the object */
799     if( (i_mode & 0x000f) == FIND_ANYWHERE )
800     {
801         vlc_object_t *p_root = p_this;
802
803         /* Find the root */
804         while( p_root->p_parent != NULL &&
805                p_root != VLC_OBJECT( p_this->p_libvlc ) )
806         {
807             p_root = p_root->p_parent;
808         }
809
810         p_found = FindObject( p_root, i_type, (i_mode & ~0x000f)|FIND_CHILD );
811         if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_libvlc ) )
812         {
813             p_found = FindObject( VLC_OBJECT( p_this->p_libvlc ),
814                                   i_type, (i_mode & ~0x000f)|FIND_CHILD );
815         }
816     }
817     else
818     {
819         p_found = FindObject( p_this, i_type, i_mode );
820     }
821
822     vlc_mutex_unlock( &structure_lock );
823
824     return p_found;
825 }
826
827 /**
828  ****************************************************************************
829  * find a named object and increment its refcount
830  *****************************************************************************
831  * This function recursively looks for a given object name. i_mode can be one
832  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
833  *****************************************************************************/
834 void * __vlc_object_find_name( vlc_object_t *p_this, const char *psz_name,
835                                int i_mode )
836 {
837     vlc_object_t *p_found;
838
839     vlc_mutex_lock( &structure_lock );
840
841     /* Avoid obvious freed object uses */
842     assert( p_this->p_internals->i_refcount > 0 );
843
844     /* If have the requested name ourselves, don't look further */
845     if( !(i_mode & FIND_STRICT)
846         && p_this->psz_object_name
847         && !strcmp( p_this->psz_object_name, psz_name )
848         && p_this->p_internals->i_refcount > 0 )
849     {
850         vlc_object_yield_locked( p_this );
851         vlc_mutex_unlock( &structure_lock );
852         return p_this;
853     }
854
855     /* Otherwise, recursively look for the object */
856     if( (i_mode & 0x000f) == FIND_ANYWHERE )
857     {
858         vlc_object_t *p_root = p_this;
859
860         /* Find the root */
861         while( p_root->p_parent != NULL &&
862                p_root != VLC_OBJECT( p_this->p_libvlc ) )
863         {
864             p_root = p_root->p_parent;
865         }
866
867         p_found = FindObjectName( p_root, psz_name,
868                                  (i_mode & ~0x000f)|FIND_CHILD );
869         if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_libvlc ) )
870         {
871             p_found = FindObjectName( VLC_OBJECT( p_this->p_libvlc ),
872                                       psz_name, (i_mode & ~0x000f)|FIND_CHILD );
873         }
874     }
875     else
876     {
877         p_found = FindObjectName( p_this, psz_name, i_mode );
878     }
879
880     vlc_mutex_unlock( &structure_lock );
881
882     return p_found;
883 }
884
885 /**
886  ****************************************************************************
887  * increment an object refcount
888  *****************************************************************************/
889
890 /* When the structure_lock is locked */
891 static void vlc_object_yield_locked( vlc_object_t *p_this )
892 {
893     vlc_assert_locked (&structure_lock);
894
895     /* Avoid obvious freed object uses */
896     assert( p_this->p_internals->i_refcount > 0 );
897
898     /* Increment the counter */
899     p_this->p_internals->i_refcount++;
900 }
901
902 /* Public function */
903 void __vlc_object_yield( vlc_object_t *p_this )
904 {
905     vlc_mutex_lock( &structure_lock );
906     vlc_object_yield_locked( p_this );
907     vlc_mutex_unlock( &structure_lock );
908 }
909
910
911 /*****************************************************************************
912  * decrement an object refcount
913  * And destroy the object if its refcount reach zero.
914  *****************************************************************************/
915 void __vlc_object_release( vlc_object_t *p_this )
916 {
917     vlc_bool_t b_should_destroy;
918
919     vlc_mutex_lock( &structure_lock );
920
921     assert( p_this->p_internals->i_refcount > 0 );
922     p_this->p_internals->i_refcount--;
923     b_should_destroy = (p_this->p_internals->i_refcount == 0);
924
925     if( b_should_destroy )
926     {
927         /* Make sure this object can't be obtained via vlc_find_object now that
928          * it is freed */
929         libvlc_global_data_t *p_libvlc_global = vlc_global();
930         int i_index;
931
932         /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
933          * useless to try and recover anything if pp_objects gets smashed. */
934         i_index = FindIndex( p_this, p_libvlc_global->pp_objects,
935                              p_libvlc_global->i_objects );
936         REMOVE_ELEM( p_libvlc_global->pp_objects,
937                      p_libvlc_global->i_objects, i_index );
938     }
939
940     vlc_mutex_unlock( &structure_lock );
941
942     if( b_should_destroy )
943         vlc_object_destroy( p_this );
944 }
945
946 /**
947  ****************************************************************************
948  * attach object to a parent object
949  *****************************************************************************
950  * This function sets p_this as a child of p_parent, and p_parent as a parent
951  * of p_this. This link can be undone using vlc_object_detach.
952  *****************************************************************************/
953 void __vlc_object_attach( vlc_object_t *p_this, vlc_object_t *p_parent )
954 {
955     if( !p_this ) return;
956
957     vlc_mutex_lock( &structure_lock );
958
959     /* Avoid obvious freed object uses */
960     assert( p_this->p_internals->i_refcount > 0 );
961
962     /* Attach the parent to its child */
963     p_this->p_parent = p_parent;
964
965     /* Attach the child to its parent */
966     INSERT_ELEM( p_parent->pp_children, p_parent->i_children,
967                  p_parent->i_children, p_this );
968
969     /* Climb up the tree to see whether we are connected with the root */
970     if( p_parent->p_internals->b_attached )
971     {
972         SetAttachment( p_this, VLC_TRUE );
973     }
974
975     vlc_mutex_unlock( &structure_lock );
976 }
977
978 /**
979  ****************************************************************************
980  * detach object from its parent
981  *****************************************************************************
982  * This function removes all links between an object and its parent.
983  *****************************************************************************/
984 void __vlc_object_detach( vlc_object_t *p_this )
985 {
986     if( !p_this ) return;
987
988     vlc_mutex_lock( &structure_lock );
989
990     if( !p_this->p_parent )
991     {
992         msg_Err( p_this, "object is not attached" );
993         vlc_mutex_unlock( &structure_lock );
994         return;
995     }
996
997     /* Climb up the tree to see whether we are connected with the root */
998     if( p_this->p_parent->p_internals->b_attached )
999     {
1000         SetAttachment( p_this, VLC_FALSE );
1001     }
1002
1003     DetachObject( p_this );
1004     vlc_mutex_unlock( &structure_lock );
1005     p_this = NULL;
1006 }
1007
1008 /**
1009  ****************************************************************************
1010  * find a list typed objects and increment their refcount
1011  *****************************************************************************
1012  * This function recursively looks for a given object type. i_mode can be one
1013  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
1014  *****************************************************************************/
1015 vlc_list_t * __vlc_list_find( vlc_object_t *p_this, int i_type, int i_mode )
1016 {
1017     vlc_list_t *p_list;
1018     vlc_object_t **pp_current, **pp_end;
1019     int i_count = 0, i_index = 0;
1020     libvlc_global_data_t *p_libvlc_global = vlc_global();
1021
1022     vlc_mutex_lock( &structure_lock );
1023
1024     /* Look for the objects */
1025     switch( i_mode & 0x000f )
1026     {
1027     case FIND_ANYWHERE:
1028         pp_current = p_libvlc_global->pp_objects;
1029         pp_end = pp_current + p_libvlc_global->i_objects;
1030
1031         for( ; pp_current < pp_end ; pp_current++ )
1032         {
1033             if( (*pp_current)->p_internals->b_attached
1034                  && (*pp_current)->i_object_type == i_type )
1035             {
1036                 i_count++;
1037             }
1038         }
1039
1040         p_list = NewList( i_count );
1041         pp_current = p_libvlc_global->pp_objects;
1042
1043         for( ; pp_current < pp_end ; pp_current++ )
1044         {
1045             if( (*pp_current)->p_internals->b_attached
1046                  && (*pp_current)->i_object_type == i_type )
1047             {
1048                 ListReplace( p_list, *pp_current, i_index );
1049                 if( i_index < i_count ) i_index++;
1050             }
1051         }
1052     break;
1053
1054     case FIND_CHILD:
1055         i_count = CountChildren( p_this, i_type );
1056         p_list = NewList( i_count );
1057
1058         /* Check allocation was successful */
1059         if( p_list->i_count != i_count )
1060         {
1061             msg_Err( p_this, "list allocation failed!" );
1062             p_list->i_count = 0;
1063             break;
1064         }
1065
1066         p_list->i_count = 0;
1067         ListChildren( p_list, p_this, i_type );
1068         break;
1069
1070     default:
1071         msg_Err( p_this, "unimplemented!" );
1072         p_list = NewList( 0 );
1073         break;
1074     }
1075
1076     vlc_mutex_unlock( &structure_lock );
1077
1078     return p_list;
1079 }
1080
1081 /*****************************************************************************
1082  * DumpCommand: print the current vlc structure
1083  *****************************************************************************
1084  * This function prints either an ASCII tree showing the connections between
1085  * vlc objects, and additional information such as their refcount, thread ID,
1086  * etc. (command "tree"), or the same data as a simple list (command "list").
1087  *****************************************************************************/
1088 static int DumpCommand( vlc_object_t *p_this, char const *psz_cmd,
1089                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
1090 {
1091     libvlc_global_data_t *p_libvlc_global = vlc_global();
1092
1093     (void)oldval; (void)p_data;
1094     if( *psz_cmd == 'l' )
1095     {
1096         vlc_mutex_lock( &structure_lock );
1097
1098         vlc_object_t **pp_current, **pp_end;
1099
1100         pp_current = p_libvlc_global->pp_objects;
1101         pp_end = pp_current + p_libvlc_global->i_objects;
1102
1103         for( ; pp_current < pp_end ; pp_current++ )
1104         {
1105             if( (*pp_current)->p_internals->b_attached )
1106             {
1107                 PrintObject( *pp_current, "" );
1108             }
1109             else
1110             {
1111                 printf( " o %.8i %s (not attached)\n",
1112                         (*pp_current)->i_object_id,
1113                         (*pp_current)->psz_object_type );
1114             }
1115         }
1116
1117         vlc_mutex_unlock( &structure_lock );
1118     }
1119     else
1120     {
1121         vlc_object_t *p_object = NULL;
1122
1123         if( *newval.psz_string )
1124         {
1125             char *end;
1126             int i_id = strtol( newval.psz_string, &end, 0 );
1127             if( end != newval.psz_string )
1128                 p_object = vlc_object_get( i_id );
1129             else
1130             {
1131                 /* try using the object's name to find it */
1132                 vlc_object_t *p_libvlc = vlc_object_get( 1 );
1133                 if( p_libvlc )
1134                 {
1135                     /* Look in p_libvlc's children tree */
1136                     p_object = vlc_object_find_name( p_libvlc,
1137                                                      newval.psz_string,
1138                                                      FIND_CHILD );
1139                     vlc_object_release( p_libvlc );
1140                 }
1141                 if( !p_object )
1142                 {
1143                     /* If it's not in libvlc, look in libvlc_global (== p_this) */
1144                     p_object = vlc_object_find_name( p_this,
1145                                                      newval.psz_string,
1146                                                      FIND_CHILD );
1147                 }
1148             }
1149
1150             if( !p_object )
1151             {
1152                 return VLC_ENOOBJ;
1153             }
1154         }
1155
1156         vlc_mutex_lock( &structure_lock );
1157
1158         if( *psz_cmd == 't' )
1159         {
1160             char psz_foo[2 * MAX_DUMPSTRUCTURE_DEPTH + 1];
1161
1162             if( !p_object )
1163                 p_object = p_this->p_libvlc ? VLC_OBJECT(p_this->p_libvlc) : p_this;
1164
1165             psz_foo[0] = '|';
1166             DumpStructure( p_object, 0, psz_foo );
1167         }
1168         else if( *psz_cmd == 'v' )
1169         {
1170             int i;
1171
1172             if( !p_object )
1173                 p_object = p_this->p_libvlc ? VLC_OBJECT(p_this->p_libvlc) : p_this;
1174
1175             PrintObject( p_object, "" );
1176
1177             if( !p_object->p_internals->i_vars )
1178                 printf( " `-o No variables\n" );
1179             for( i = 0; i < p_object->p_internals->i_vars; i++ )
1180             {
1181                 variable_t *p_var = p_object->p_internals->p_vars + i;
1182
1183                 const char *psz_type = "unknown";
1184                 switch( p_var->i_type & VLC_VAR_TYPE )
1185                 {
1186 #define MYCASE( type, nice )                \
1187                     case VLC_VAR_ ## type:  \
1188                         psz_type = nice;    \
1189                         break;
1190                     MYCASE( VOID, "void" );
1191                     MYCASE( BOOL, "bool" );
1192                     MYCASE( INTEGER, "integer" );
1193                     MYCASE( HOTKEY, "hotkey" );
1194                     MYCASE( STRING, "string" );
1195                     MYCASE( MODULE, "module" );
1196                     MYCASE( FILE, "file" );
1197                     MYCASE( DIRECTORY, "directory" );
1198                     MYCASE( VARIABLE, "variable" );
1199                     MYCASE( FLOAT, "float" );
1200                     MYCASE( TIME, "time" );
1201                     MYCASE( ADDRESS, "address" );
1202                     MYCASE( MUTEX, "mutex" );
1203                     MYCASE( LIST, "list" );
1204 #undef MYCASE
1205                 }
1206                 printf( " %c-o \"%s\" (%s",
1207                         i + 1 == p_object->p_internals->i_vars ? '`' : '|',
1208                         p_var->psz_name, psz_type );
1209                 if( p_var->psz_text )
1210                     printf( ", %s", p_var->psz_text );
1211                 printf( ")" );
1212                 if( p_var->i_type & VLC_VAR_ISCOMMAND )
1213                     printf( ", command" );
1214                 if( p_var->i_entries )
1215                     printf( ", %d callbacks", p_var->i_entries );
1216                 switch( p_var->i_type & 0x00f0 )
1217                 {
1218                     case VLC_VAR_VOID:
1219                     case VLC_VAR_MUTEX:
1220                         break;
1221                     case VLC_VAR_BOOL:
1222                         printf( ": %s", p_var->val.b_bool ? "true" : "false" );
1223                         break;
1224                     case VLC_VAR_INTEGER:
1225                         printf( ": %d", p_var->val.i_int );
1226                         break;
1227                     case VLC_VAR_STRING:
1228                         printf( ": \"%s\"", p_var->val.psz_string );
1229                         break;
1230                     case VLC_VAR_FLOAT:
1231                         printf( ": %f", p_var->val.f_float );
1232                         break;
1233                     case VLC_VAR_TIME:
1234                         printf( ": " I64Fi, (int64_t)p_var->val.i_time );
1235                         break;
1236                     case VLC_VAR_ADDRESS:
1237                         printf( ": %p", p_var->val.p_address );
1238                         break;
1239                     case VLC_VAR_LIST:
1240                         printf( ": TODO" );
1241                         break;
1242                 }
1243                 printf( "\n" );
1244             }
1245         }
1246
1247         vlc_mutex_unlock( &structure_lock );
1248
1249         if( *newval.psz_string )
1250         {
1251             vlc_object_release( p_object );
1252         }
1253     }
1254
1255     return VLC_SUCCESS;
1256 }
1257
1258 /*****************************************************************************
1259  * vlc_list_release: free a list previously allocated by vlc_list_find
1260  *****************************************************************************
1261  * This function decreases the refcount of all objects in the list and
1262  * frees the list.
1263  *****************************************************************************/
1264 void vlc_list_release( vlc_list_t *p_list )
1265 {
1266     int i_index;
1267
1268     for( i_index = 0; i_index < p_list->i_count; i_index++ )
1269     {
1270         vlc_object_release( p_list->p_values[i_index].p_object );
1271     }
1272
1273     free( p_list->p_values );
1274     free( p_list );
1275 }
1276
1277 /* Following functions are local */
1278
1279 /*****************************************************************************
1280  * FindIndex: find the index of an object in an array of objects
1281  *****************************************************************************
1282  * This function assumes that p_this can be found in pp_objects. It will not
1283  * crash if p_this cannot be found, but will return a wrong value. It is your
1284  * duty to check the return value if you are not certain that the object could
1285  * be found for sure.
1286  *****************************************************************************/
1287 static int FindIndex( vlc_object_t *p_this,
1288                       vlc_object_t **pp_objects, int i_count )
1289 {
1290     int i_middle = i_count / 2;
1291
1292     if( i_count == 0 )
1293     {
1294         return 0;
1295     }
1296
1297     if( pp_objects[i_middle] == p_this )
1298     {
1299         return i_middle;
1300     }
1301
1302     if( i_count == 1 )
1303     {
1304         return 0;
1305     }
1306
1307     /* We take advantage of the sorted array */
1308     if( pp_objects[i_middle]->i_object_id < p_this->i_object_id )
1309     {
1310         return i_middle + FindIndex( p_this, pp_objects + i_middle,
1311                                              i_count - i_middle );
1312     }
1313     else
1314     {
1315         return FindIndex( p_this, pp_objects, i_middle );
1316     }
1317 }
1318
1319 static vlc_object_t * FindObject( vlc_object_t *p_this, int i_type, int i_mode )
1320 {
1321     int i;
1322     vlc_object_t *p_tmp;
1323
1324     switch( i_mode & 0x000f )
1325     {
1326     case FIND_PARENT:
1327         p_tmp = p_this->p_parent;
1328         if( p_tmp )
1329         {
1330             if( p_tmp->i_object_type == i_type
1331                 && p_tmp->p_internals->i_refcount > 0 )
1332             {
1333                 vlc_object_yield_locked( p_tmp );
1334                 return p_tmp;
1335             }
1336             else
1337             {
1338                 return FindObject( p_tmp, i_type, i_mode );
1339             }
1340         }
1341         break;
1342
1343     case FIND_CHILD:
1344         for( i = p_this->i_children; i--; )
1345         {
1346             p_tmp = p_this->pp_children[i];
1347             if( p_tmp->i_object_type == i_type
1348                 && p_tmp->p_internals->i_refcount > 0 )
1349             {
1350                 vlc_object_yield_locked( p_tmp );
1351                 return p_tmp;
1352             }
1353             else if( p_tmp->i_children )
1354             {
1355                 p_tmp = FindObject( p_tmp, i_type, i_mode );
1356                 if( p_tmp )
1357                 {
1358                     return p_tmp;
1359                 }
1360             }
1361         }
1362         break;
1363
1364     case FIND_ANYWHERE:
1365         /* Handled in vlc_object_find */
1366         break;
1367     }
1368
1369     return NULL;
1370 }
1371
1372 static vlc_object_t * FindObjectName( vlc_object_t *p_this,
1373                                       const char *psz_name,
1374                                       int i_mode )
1375 {
1376     int i;
1377     vlc_object_t *p_tmp;
1378
1379     switch( i_mode & 0x000f )
1380     {
1381     case FIND_PARENT:
1382         p_tmp = p_this->p_parent;
1383         if( p_tmp )
1384         {
1385             if( p_tmp->psz_object_name
1386                 && !strcmp( p_tmp->psz_object_name, psz_name )
1387                 && p_tmp->p_internals->i_refcount > 0 )
1388             {
1389                 vlc_object_yield_locked( p_tmp );
1390                 return p_tmp;
1391             }
1392             else
1393             {
1394                 return FindObjectName( p_tmp, psz_name, i_mode );
1395             }
1396         }
1397         break;
1398
1399     case FIND_CHILD:
1400         for( i = p_this->i_children; i--; )
1401         {
1402             p_tmp = p_this->pp_children[i];
1403             if( p_tmp->psz_object_name
1404                 && !strcmp( p_tmp->psz_object_name, psz_name )
1405                 && p_tmp->p_internals->i_refcount > 0 )
1406             {
1407                 vlc_object_yield_locked( p_tmp );
1408                 return p_tmp;
1409             }
1410             else if( p_tmp->i_children )
1411             {
1412                 p_tmp = FindObjectName( p_tmp, psz_name, i_mode );
1413                 if( p_tmp )
1414                 {
1415                     return p_tmp;
1416                 }
1417             }
1418         }
1419         break;
1420
1421     case FIND_ANYWHERE:
1422         /* Handled in vlc_object_find */
1423         break;
1424     }
1425
1426     return NULL;
1427 }
1428
1429 static void DetachObject( vlc_object_t *p_this )
1430 {
1431     vlc_object_t *p_parent = p_this->p_parent;
1432     int i_index, i;
1433
1434     /* Remove p_this's parent */
1435     p_this->p_parent = NULL;
1436
1437     /* Remove all of p_parent's children which are p_this */
1438     for( i_index = p_parent->i_children ; i_index-- ; )
1439     {
1440         if( p_parent->pp_children[i_index] == p_this )
1441         {
1442             p_parent->i_children--;
1443             for( i = i_index ; i < p_parent->i_children ; i++ )
1444             {
1445                 p_parent->pp_children[i] = p_parent->pp_children[i+1];
1446             }
1447         }
1448     }
1449
1450     if( p_parent->i_children )
1451     {
1452         p_parent->pp_children = (vlc_object_t **)realloc( p_parent->pp_children,
1453                                p_parent->i_children * sizeof(vlc_object_t *) );
1454     }
1455     else
1456     {
1457         free( p_parent->pp_children );
1458         p_parent->pp_children = NULL;
1459     }
1460 }
1461
1462 /*****************************************************************************
1463  * SetAttachment: recursively set the b_attached flag of a subtree.
1464  *****************************************************************************
1465  * This function is used by the attach and detach functions to propagate
1466  * the b_attached flag in a subtree.
1467  *****************************************************************************/
1468 static void SetAttachment( vlc_object_t *p_this, vlc_bool_t b_attached )
1469 {
1470     int i_index;
1471
1472     for( i_index = p_this->i_children ; i_index-- ; )
1473     {
1474         SetAttachment( p_this->pp_children[i_index], b_attached );
1475     }
1476
1477     p_this->p_internals->b_attached = b_attached;
1478 }
1479
1480 static void PrintObject( vlc_object_t *p_this, const char *psz_prefix )
1481 {
1482     char psz_children[20], psz_refcount[20], psz_thread[30], psz_name[50],
1483          psz_parent[20];
1484
1485     psz_name[0] = '\0';
1486     if( p_this->psz_object_name )
1487     {
1488         snprintf( psz_name, 49, " \"%s\"", p_this->psz_object_name );
1489         if( psz_name[48] )
1490             psz_name[48] = '\"';
1491     }
1492
1493     psz_children[0] = '\0';
1494     switch( p_this->i_children )
1495     {
1496         case 0:
1497             break;
1498         case 1:
1499             strcpy( psz_children, ", 1 child" );
1500             break;
1501         default:
1502             snprintf( psz_children, 19, ", %i children", p_this->i_children );
1503             break;
1504     }
1505
1506     psz_refcount[0] = '\0';
1507     if( p_this->p_internals->i_refcount > 0 )
1508         snprintf( psz_refcount, 19, ", refcount %u",
1509                   p_this->p_internals->i_refcount );
1510
1511     psz_thread[0] = '\0';
1512     if( p_this->p_internals->b_thread )
1513         snprintf( psz_thread, 29, " (thread %u)",
1514 #if defined(WIN32) || defined(UNDER_CE)
1515                   (unsigned)p_this->p_internals->thread_id.id );
1516 #else
1517                   (unsigned)p_this->p_internals->thread_id );
1518 #endif
1519
1520     psz_parent[0] = '\0';
1521     if( p_this->p_parent )
1522         snprintf( psz_parent, 19, ", parent %i", p_this->p_parent->i_object_id );
1523
1524     printf( " %so %.8i %s%s%s%s%s%s\n", psz_prefix,
1525             p_this->i_object_id, p_this->psz_object_type,
1526             psz_name, psz_thread, psz_refcount, psz_children,
1527             psz_parent );
1528 }
1529
1530 static void DumpStructure( vlc_object_t *p_this, int i_level, char *psz_foo )
1531 {
1532     int i;
1533     char i_back = psz_foo[i_level];
1534     psz_foo[i_level] = '\0';
1535
1536     PrintObject( p_this, psz_foo );
1537
1538     psz_foo[i_level] = i_back;
1539
1540     if( i_level / 2 >= MAX_DUMPSTRUCTURE_DEPTH )
1541     {
1542         msg_Warn( p_this, "structure tree is too deep" );
1543         return;
1544     }
1545
1546     for( i = 0 ; i < p_this->i_children ; i++ )
1547     {
1548         if( i_level )
1549         {
1550             psz_foo[i_level-1] = ' ';
1551
1552             if( psz_foo[i_level-2] == '`' )
1553             {
1554                 psz_foo[i_level-2] = ' ';
1555             }
1556         }
1557
1558         if( i == p_this->i_children - 1 )
1559         {
1560             psz_foo[i_level] = '`';
1561         }
1562         else
1563         {
1564             psz_foo[i_level] = '|';
1565         }
1566
1567         psz_foo[i_level+1] = '-';
1568         psz_foo[i_level+2] = '\0';
1569
1570         DumpStructure( p_this->pp_children[i], i_level + 2, psz_foo );
1571     }
1572 }
1573
1574 static vlc_list_t * NewList( int i_count )
1575 {
1576     vlc_list_t * p_list = (vlc_list_t *)malloc( sizeof( vlc_list_t ) );
1577     if( p_list == NULL )
1578     {
1579         return NULL;
1580     }
1581
1582     p_list->i_count = i_count;
1583
1584     if( i_count == 0 )
1585     {
1586         p_list->p_values = NULL;
1587         return p_list;
1588     }
1589
1590     p_list->p_values = malloc( i_count * sizeof( vlc_value_t ) );
1591     if( p_list->p_values == NULL )
1592     {
1593         p_list->i_count = 0;
1594         return p_list;
1595     }
1596
1597     return p_list;
1598 }
1599
1600 static void ListReplace( vlc_list_t *p_list, vlc_object_t *p_object,
1601                          int i_index )
1602 {
1603     if( p_list == NULL || i_index >= p_list->i_count )
1604     {
1605         return;
1606     }
1607
1608     vlc_object_yield_locked( p_object );
1609
1610     p_list->p_values[i_index].p_object = p_object;
1611
1612     return;
1613 }
1614
1615 /*static void ListAppend( vlc_list_t *p_list, vlc_object_t *p_object )
1616 {
1617     if( p_list == NULL )
1618     {
1619         return;
1620     }
1621
1622     p_list->p_values = realloc( p_list->p_values, (p_list->i_count + 1)
1623                                 * sizeof( vlc_value_t ) );
1624     if( p_list->p_values == NULL )
1625     {
1626         p_list->i_count = 0;
1627         return;
1628     }
1629
1630     vlc_object_yield_locked( p_object );
1631
1632     p_list->p_values[p_list->i_count].p_object = p_object;
1633     p_list->i_count++;
1634
1635     return;
1636 }*/
1637
1638 static int CountChildren( vlc_object_t *p_this, int i_type )
1639 {
1640     vlc_object_t *p_tmp;
1641     int i, i_count = 0;
1642
1643     for( i = 0; i < p_this->i_children; i++ )
1644     {
1645         p_tmp = p_this->pp_children[i];
1646
1647         if( p_tmp->i_object_type == i_type )
1648         {
1649             i_count++;
1650         }
1651
1652         if( p_tmp->i_children )
1653         {
1654             i_count += CountChildren( p_tmp, i_type );
1655         }
1656     }
1657
1658     return i_count;
1659 }
1660
1661 static void ListChildren( vlc_list_t *p_list, vlc_object_t *p_this, int i_type )
1662 {
1663     vlc_object_t *p_tmp;
1664     int i;
1665
1666     for( i = 0; i < p_this->i_children; i++ )
1667     {
1668         p_tmp = p_this->pp_children[i];
1669
1670         if( p_tmp->i_object_type == i_type )
1671         {
1672             ListReplace( p_list, p_tmp, p_list->i_count++ );
1673         }
1674
1675         if( p_tmp->i_children )
1676         {
1677             ListChildren( p_list, p_tmp, i_type );
1678         }
1679     }
1680 }