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