]> git.sesse.net Git - vlc/blob - src/misc/objects.c
vlc_object_get(): removes unused parameter
[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[0] != -1 )
454         close( p_priv->pipes[0] );
455     if( p_priv->pipes[1] != -1 )
456         close( p_priv->pipes[1] );
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 whenever
532  * an object is signaled. This can be used to wait for VLC object events
533  * inside select(), poll() loops or frameworks providing an event loop.
534  *
535  * Note that the pipe will remain the same for the lifetime of the object.
536  * DO NOT close it yourself. Ever.
537  *
538  * DO NOT try to read from the pipe either: call vlc_object_wait() instead.
539  * Assuming the pipe is readable, vlc_object_wait() will not block.
540  * Also note that, as with vlc_object_wait(), there may be spurious wakeups.
541  *
542  * @param obj object that would be signaled
543  * @return a readable pipe descriptor, or -1 on error.
544  */
545 int __vlc_object_waitpipe( vlc_object_t *obj )
546 {
547     int pfd[2] = { -1, -1 };
548     struct vlc_object_internals_t *internals = obj->p_internals;
549     vlc_bool_t race = VLC_FALSE, signaled = VLC_FALSE;
550
551     vlc_spin_lock (&internals->spin);
552     if (internals->pipes[0] == -1)
553     {
554         /* This can only ever happen if someone killed us without locking: */
555         assert (internals->pipes[1] == -1);
556         vlc_spin_unlock (&internals->spin);
557
558         if (pipe (pfd))
559             return -1;
560
561         vlc_spin_lock (&internals->spin);
562         signaled = internals->b_signaled;
563         if (internals->pipes[0] == -1)
564         {
565             internals->pipes[0] = pfd[0];
566             internals->pipes[1] = pfd[1];
567         }
568         else
569             race = VLC_TRUE;
570     }
571     vlc_spin_unlock (&internals->spin);
572
573     if (race)
574     {   /* Race condition: two threads call pipe() - unlikely */
575         close (pfd[0]);
576         close (pfd[1]);
577     }
578
579     if (signaled)
580         /* Race condition: lc_object_signal() already invoked! */
581         while (write (internals->pipes[1], &(char){ 0 }, 1) < 0);
582
583     return internals->pipes[0];
584 }
585
586
587 /**
588  * Waits for the object to be signaled (using vlc_object_signal()).
589  * If the object already has a signal pending, this function will return
590  * immediately. It is asserted that the caller holds the object lock.
591  *
592  * @return true if the object is dying and should terminate.
593  */
594 vlc_bool_t __vlc_object_wait( vlc_object_t *obj )
595 {
596     int fd;
597
598     vlc_assert_locked( &obj->object_lock );
599
600     fd = obj->p_internals->pipes[0];
601     if (fd != -1)
602     {
603         while (read (fd, &(char){ 0 }, 1)  < 0);
604         return obj->b_die;
605     }
606
607     vlc_cond_wait( &obj->object_wait, &obj->object_lock );
608     obj->p_internals->b_signaled = VLC_FALSE;
609     return obj->b_die;
610 }
611
612
613 /**
614  * Waits for the object to be signaled (using vlc_object_signal()), or for
615  * a timer to expire.
616  * If the object already has a signal pending, this function will return
617  * immediately. It is asserted that the caller holds the object lock.
618  *
619  * @return negative if the object is dying and should terminate,
620  * positive if the the object has been signaled but is not dying,
621  * 0 if timeout has been reached.
622  */
623 int __vlc_object_timedwait( vlc_object_t *obj, mtime_t deadline )
624 {
625     int v;
626
627     vlc_assert_locked( &obj->object_lock );
628     v = vlc_cond_timedwait( &obj->object_wait, &obj->object_lock, deadline );
629     if( v == 0 ) /* signaled */
630         return obj->b_die ? -1 : 1;
631     return 0;
632 }
633
634
635 /**
636  * Checks whether an object has been "killed".
637  * The object lock must be held.
638  *
639  * Typical code for an object thread could be:
640  *
641    vlc_object_lock (self);
642    ...initialization...
643    while (vlc_object_alive (self))
644    {
645        ...preprocessing...
646
647        if (vlc_object_wait (self))
648            continue;
649
650        ...postprocessing...
651    }
652    ...deinitialization...
653    vlc_object_unlock (self);
654  *
655  *
656  * @return true iff the object has not been killed yet
657  */
658 vlc_bool_t __vlc_object_alive( vlc_object_t *obj )
659 {
660     vlc_assert_locked( &obj->object_lock );
661     return !obj->b_die;
662 }
663
664
665 /**
666  * Signals an object for which the lock is held.
667  */
668 void __vlc_object_signal_unlocked( vlc_object_t *obj )
669 {
670     struct vlc_object_internals_t *internals = obj->p_internals;
671     int fd;
672
673     vlc_assert_locked (&obj->object_lock);
674
675     vlc_spin_lock (&internals->spin);
676     fd = internals->pipes[1];
677     internals->b_signaled = VLC_TRUE;
678     vlc_spin_unlock (&internals->spin);
679
680     if( fd != -1 )
681         while( write( fd, &(char){ 0 }, 1 ) < 0 );
682
683     vlc_cond_signal( &obj->object_wait );
684 }
685
686
687 /**
688  * Requests termination of an object.
689  * If the object is LibVLC, also request to terminate all its children.
690  */
691 void __vlc_object_kill( vlc_object_t *p_this )
692 {
693     vlc_mutex_lock( &p_this->object_lock );
694     p_this->b_die = VLC_TRUE;
695
696     if( p_this->i_object_type == VLC_OBJECT_LIBVLC )
697         for( int i = 0; i < p_this->i_children ; i++ )
698             vlc_object_kill( p_this->pp_children[i] );
699
700     vlc_object_signal_unlocked( p_this );
701     vlc_mutex_unlock( &p_this->object_lock );
702 }
703
704
705 /**
706  * find an object given its ID
707  *
708  * This function looks for the object whose i_object_id field is i_id. We
709  * use a dichotomy so that lookups are in log2(n).
710  *****************************************************************************/
711 void * vlc_object_get( int i_id )
712 {
713     int i_max, i_middle;
714     vlc_object_t **pp_objects;
715     libvlc_global_data_t *p_libvlc_global = vlc_global();
716
717     vlc_mutex_lock( &structure_lock );
718
719     pp_objects = p_libvlc_global->pp_objects;
720
721     /* Perform our dichotomy */
722     for( i_max = p_libvlc_global->i_objects - 1 ; ; )
723     {
724         i_middle = i_max / 2;
725
726         if( pp_objects[i_middle]->i_object_id > i_id )
727         {
728             i_max = i_middle;
729         }
730         else if( pp_objects[i_middle]->i_object_id < i_id )
731         {
732             if( i_middle )
733             {
734                 pp_objects += i_middle;
735                 i_max -= i_middle;
736             }
737             else
738             {
739                 /* This happens when there are only two remaining objects */
740                 if( pp_objects[i_middle+1]->i_object_id == i_id )
741                 {
742                     vlc_mutex_unlock( &structure_lock );
743                     pp_objects[i_middle+1]->p_internals->i_refcount++;
744                     return pp_objects[i_middle+1];
745                 }
746                 break;
747             }
748         }
749         else
750         {
751             vlc_mutex_unlock( &structure_lock );
752             pp_objects[i_middle]->p_internals->i_refcount++;
753             return pp_objects[i_middle];
754         }
755
756         if( i_max == 0 )
757         {
758             /* this means that i_max == i_middle, and since we have already
759              * tested pp_objects[i_middle]), p_found is properly set. */
760             break;
761         }
762     }
763
764     vlc_mutex_unlock( &structure_lock );
765     return NULL;
766 }
767
768 /**
769  ****************************************************************************
770  * find a typed object and increment its refcount
771  *****************************************************************************
772  * This function recursively looks for a given object type. i_mode can be one
773  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
774  *****************************************************************************/
775 void * __vlc_object_find( vlc_object_t *p_this, int i_type, int i_mode )
776 {
777     vlc_object_t *p_found;
778
779     vlc_mutex_lock( &structure_lock );
780
781     /* If we are of the requested type ourselves, don't look further */
782     if( !(i_mode & FIND_STRICT) && p_this->i_object_type == i_type )
783     {
784         p_this->p_internals->i_refcount++;
785         vlc_mutex_unlock( &structure_lock );
786         return p_this;
787     }
788
789     /* Otherwise, recursively look for the object */
790     if( (i_mode & 0x000f) == FIND_ANYWHERE )
791     {
792         vlc_object_t *p_root = p_this;
793
794         /* Find the root */
795         while( p_root->p_parent != NULL &&
796                p_root != VLC_OBJECT( p_this->p_libvlc ) )
797         {
798             p_root = p_root->p_parent;
799         }
800
801         p_found = FindObject( p_root, i_type, (i_mode & ~0x000f)|FIND_CHILD );
802         if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_libvlc ) )
803         {
804             p_found = FindObject( VLC_OBJECT( p_this->p_libvlc ),
805                                   i_type, (i_mode & ~0x000f)|FIND_CHILD );
806         }
807     }
808     else
809     {
810         p_found = FindObject( p_this, i_type, i_mode );
811     }
812
813     vlc_mutex_unlock( &structure_lock );
814
815     return p_found;
816 }
817
818 /**
819  ****************************************************************************
820  * find a named object and increment its refcount
821  *****************************************************************************
822  * This function recursively looks for a given object name. i_mode can be one
823  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
824  *****************************************************************************/
825 void * __vlc_object_find_name( vlc_object_t *p_this, const char *psz_name,
826                                int i_mode )
827 {
828     vlc_object_t *p_found;
829
830     vlc_mutex_lock( &structure_lock );
831
832     /* If have the requested name ourselves, don't look further */
833     if( !(i_mode & FIND_STRICT)
834         && p_this->psz_object_name
835         && !strcmp( p_this->psz_object_name, psz_name ) )
836     {
837         p_this->p_internals->i_refcount++;
838         vlc_mutex_unlock( &structure_lock );
839         return p_this;
840     }
841
842     /* Otherwise, recursively look for the object */
843     if( (i_mode & 0x000f) == FIND_ANYWHERE )
844     {
845         vlc_object_t *p_root = p_this;
846
847         /* Find the root */
848         while( p_root->p_parent != NULL &&
849                p_root != VLC_OBJECT( p_this->p_libvlc ) )
850         {
851             p_root = p_root->p_parent;
852         }
853
854         p_found = FindObjectName( p_root, psz_name,
855                                  (i_mode & ~0x000f)|FIND_CHILD );
856         if( p_found == NULL && p_root != VLC_OBJECT( p_this->p_libvlc ) )
857         {
858             p_found = FindObjectName( VLC_OBJECT( p_this->p_libvlc ),
859                                       psz_name, (i_mode & ~0x000f)|FIND_CHILD );
860         }
861     }
862     else
863     {
864         p_found = FindObjectName( p_this, psz_name, i_mode );
865     }
866
867     vlc_mutex_unlock( &structure_lock );
868
869     return p_found;
870 }
871
872 /**
873  ****************************************************************************
874  * increment an object refcount
875  *****************************************************************************/
876 void __vlc_object_yield( vlc_object_t *p_this )
877 {
878     vlc_mutex_lock( &structure_lock );
879     p_this->p_internals->i_refcount++;
880     vlc_mutex_unlock( &structure_lock );
881 }
882
883 static inline void Release( vlc_object_t *obj )
884 {
885     assert( obj->p_internals->i_refcount > 0 );
886     obj->p_internals->i_refcount--;
887 }
888
889 /*****************************************************************************
890  * decrement an object refcount
891  *****************************************************************************/
892 void __vlc_object_release( vlc_object_t *p_this )
893 {
894     vlc_mutex_lock( &structure_lock );
895     Release( p_this );
896     vlc_mutex_unlock( &structure_lock );
897 }
898
899 /**
900  ****************************************************************************
901  * attach object to a parent object
902  *****************************************************************************
903  * This function sets p_this as a child of p_parent, and p_parent as a parent
904  * of p_this. This link can be undone using vlc_object_detach.
905  *****************************************************************************/
906 void __vlc_object_attach( vlc_object_t *p_this, vlc_object_t *p_parent )
907 {
908     if( !p_this ) return;
909
910     vlc_mutex_lock( &structure_lock );
911
912     /* Attach the parent to its child */
913     p_this->p_parent = p_parent;
914
915     /* Attach the child to its parent */
916     INSERT_ELEM( p_parent->pp_children, p_parent->i_children,
917                  p_parent->i_children, p_this );
918
919     /* Climb up the tree to see whether we are connected with the root */
920     if( p_parent->p_internals->b_attached )
921     {
922         SetAttachment( p_this, VLC_TRUE );
923     }
924
925     vlc_mutex_unlock( &structure_lock );
926 }
927
928 /**
929  ****************************************************************************
930  * detach object from its parent
931  *****************************************************************************
932  * This function removes all links between an object and its parent.
933  *****************************************************************************/
934 void __vlc_object_detach( vlc_object_t *p_this )
935 {
936     if( !p_this ) return;
937
938     vlc_mutex_lock( &structure_lock );
939     if( !p_this->p_parent )
940     {
941         msg_Err( p_this, "object is not attached" );
942         vlc_mutex_unlock( &structure_lock );
943         return;
944     }
945
946     /* Climb up the tree to see whether we are connected with the root */
947     if( p_this->p_parent->p_internals->b_attached )
948     {
949         SetAttachment( p_this, VLC_FALSE );
950     }
951
952     DetachObject( p_this );
953     vlc_mutex_unlock( &structure_lock );
954     p_this = NULL;
955 }
956
957 /**
958  ****************************************************************************
959  * find a list typed objects and increment their refcount
960  *****************************************************************************
961  * This function recursively looks for a given object type. i_mode can be one
962  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
963  *****************************************************************************/
964 vlc_list_t * __vlc_list_find( vlc_object_t *p_this, int i_type, int i_mode )
965 {
966     vlc_list_t *p_list;
967     vlc_object_t **pp_current, **pp_end;
968     int i_count = 0, i_index = 0;
969     libvlc_global_data_t *p_libvlc_global = vlc_global();
970
971     vlc_mutex_lock( &structure_lock );
972
973     /* Look for the objects */
974     switch( i_mode & 0x000f )
975     {
976     case FIND_ANYWHERE:
977         pp_current = p_libvlc_global->pp_objects;
978         pp_end = pp_current + p_libvlc_global->i_objects;
979
980         for( ; pp_current < pp_end ; pp_current++ )
981         {
982             if( (*pp_current)->p_internals->b_attached
983                  && (*pp_current)->i_object_type == i_type )
984             {
985                 i_count++;
986             }
987         }
988
989         p_list = NewList( i_count );
990         pp_current = p_libvlc_global->pp_objects;
991
992         for( ; pp_current < pp_end ; pp_current++ )
993         {
994             if( (*pp_current)->p_internals->b_attached
995                  && (*pp_current)->i_object_type == i_type )
996             {
997                 ListReplace( p_list, *pp_current, i_index );
998                 if( i_index < i_count ) i_index++;
999             }
1000         }
1001     break;
1002
1003     case FIND_CHILD:
1004         i_count = CountChildren( p_this, i_type );
1005         p_list = NewList( i_count );
1006
1007         /* Check allocation was successful */
1008         if( p_list->i_count != i_count )
1009         {
1010             msg_Err( p_this, "list allocation failed!" );
1011             p_list->i_count = 0;
1012             break;
1013         }
1014
1015         p_list->i_count = 0;
1016         ListChildren( p_list, p_this, i_type );
1017         break;
1018
1019     default:
1020         msg_Err( p_this, "unimplemented!" );
1021         p_list = NewList( 0 );
1022         break;
1023     }
1024
1025     vlc_mutex_unlock( &structure_lock );
1026
1027     return p_list;
1028 }
1029
1030 /*****************************************************************************
1031  * DumpCommand: print the current vlc structure
1032  *****************************************************************************
1033  * This function prints either an ASCII tree showing the connections between
1034  * vlc objects, and additional information such as their refcount, thread ID,
1035  * etc. (command "tree"), or the same data as a simple list (command "list").
1036  *****************************************************************************/
1037 static int DumpCommand( vlc_object_t *p_this, char const *psz_cmd,
1038                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
1039 {
1040     libvlc_global_data_t *p_libvlc_global = vlc_global();
1041
1042     (void)oldval; (void)p_data;
1043     if( *psz_cmd == 'l' )
1044     {
1045         vlc_mutex_lock( &structure_lock );
1046
1047         vlc_object_t **pp_current, **pp_end;
1048
1049         pp_current = p_libvlc_global->pp_objects;
1050         pp_end = pp_current + p_libvlc_global->i_objects;
1051
1052         for( ; pp_current < pp_end ; pp_current++ )
1053         {
1054             if( (*pp_current)->p_internals->b_attached )
1055             {
1056                 PrintObject( *pp_current, "" );
1057             }
1058             else
1059             {
1060                 printf( " o %.8i %s (not attached)\n",
1061                         (*pp_current)->i_object_id,
1062                         (*pp_current)->psz_object_type );
1063             }
1064         }
1065
1066         vlc_mutex_unlock( &structure_lock );
1067     }
1068     else
1069     {
1070         vlc_object_t *p_object = NULL;
1071
1072         if( *newval.psz_string )
1073         {
1074             char *end;
1075             int i_id = strtol( newval.psz_string, &end, 0 );
1076             if( end != newval.psz_string )
1077                 p_object = vlc_object_get( i_id );
1078             else
1079             {
1080                 /* try using the object's name to find it */
1081                 vlc_object_t *p_libvlc = vlc_object_get( 1 );
1082                 if( p_libvlc )
1083                 {
1084                     /* Look in p_libvlc's children tree */
1085                     p_object = vlc_object_find_name( p_libvlc,
1086                                                      newval.psz_string,
1087                                                      FIND_CHILD );
1088                     vlc_object_release( p_libvlc );
1089                 }
1090                 if( !p_object )
1091                 {
1092                     /* If it's not in libvlc, look in libvlc_global (== p_this) */
1093                     p_object = vlc_object_find_name( p_this,
1094                                                      newval.psz_string,
1095                                                      FIND_CHILD );
1096                 }
1097             }
1098
1099             if( !p_object )
1100             {
1101                 return VLC_ENOOBJ;
1102             }
1103         }
1104
1105         vlc_mutex_lock( &structure_lock );
1106
1107         if( *psz_cmd == 't' )
1108         {
1109             char psz_foo[2 * MAX_DUMPSTRUCTURE_DEPTH + 1];
1110
1111             if( !p_object )
1112                 p_object = p_this->p_libvlc ? VLC_OBJECT(p_this->p_libvlc) : p_this;
1113
1114             psz_foo[0] = '|';
1115             DumpStructure( p_object, 0, psz_foo );
1116         }
1117         else if( *psz_cmd == 'v' )
1118         {
1119             int i;
1120
1121             if( !p_object )
1122                 p_object = p_this->p_libvlc ? VLC_OBJECT(p_this->p_libvlc) : p_this;
1123
1124             PrintObject( p_object, "" );
1125
1126             if( !p_object->p_internals->i_vars )
1127                 printf( " `-o No variables\n" );
1128             for( i = 0; i < p_object->p_internals->i_vars; i++ )
1129             {
1130                 variable_t *p_var = p_object->p_internals->p_vars + i;
1131
1132                 const char *psz_type = "unknown";
1133                 switch( p_var->i_type & VLC_VAR_TYPE )
1134                 {
1135 #define MYCASE( type, nice )                \
1136                     case VLC_VAR_ ## type:  \
1137                         psz_type = nice;    \
1138                         break;
1139                     MYCASE( VOID, "void" );
1140                     MYCASE( BOOL, "bool" );
1141                     MYCASE( INTEGER, "integer" );
1142                     MYCASE( HOTKEY, "hotkey" );
1143                     MYCASE( STRING, "string" );
1144                     MYCASE( MODULE, "module" );
1145                     MYCASE( FILE, "file" );
1146                     MYCASE( DIRECTORY, "directory" );
1147                     MYCASE( VARIABLE, "variable" );
1148                     MYCASE( FLOAT, "float" );
1149                     MYCASE( TIME, "time" );
1150                     MYCASE( ADDRESS, "address" );
1151                     MYCASE( MUTEX, "mutex" );
1152                     MYCASE( LIST, "list" );
1153 #undef MYCASE
1154                 }
1155                 printf( " %c-o \"%s\" (%s",
1156                         i + 1 == p_object->p_internals->i_vars ? '`' : '|',
1157                         p_var->psz_name, psz_type );
1158                 if( p_var->psz_text )
1159                     printf( ", %s", p_var->psz_text );
1160                 printf( ")" );
1161                 if( p_var->i_type & VLC_VAR_ISCOMMAND )
1162                     printf( ", command" );
1163                 if( p_var->i_entries )
1164                     printf( ", %d callbacks", p_var->i_entries );
1165                 switch( p_var->i_type & 0x00f0 )
1166                 {
1167                     case VLC_VAR_VOID:
1168                     case VLC_VAR_MUTEX:
1169                         break;
1170                     case VLC_VAR_BOOL:
1171                         printf( ": %s", p_var->val.b_bool ? "true" : "false" );
1172                         break;
1173                     case VLC_VAR_INTEGER:
1174                         printf( ": %d", p_var->val.i_int );
1175                         break;
1176                     case VLC_VAR_STRING:
1177                         printf( ": \"%s\"", p_var->val.psz_string );
1178                         break;
1179                     case VLC_VAR_FLOAT:
1180                         printf( ": %f", p_var->val.f_float );
1181                         break;
1182                     case VLC_VAR_TIME:
1183                         printf( ": " I64Fi, (int64_t)p_var->val.i_time );
1184                         break;
1185                     case VLC_VAR_ADDRESS:
1186                         printf( ": %p", p_var->val.p_address );
1187                         break;
1188                     case VLC_VAR_LIST:
1189                         printf( ": TODO" );
1190                         break;
1191                 }
1192                 printf( "\n" );
1193             }
1194         }
1195
1196         vlc_mutex_unlock( &structure_lock );
1197
1198         if( *newval.psz_string )
1199         {
1200             vlc_object_release( p_object );
1201         }
1202     }
1203
1204     return VLC_SUCCESS;
1205 }
1206
1207 /*****************************************************************************
1208  * vlc_list_release: free a list previously allocated by vlc_list_find
1209  *****************************************************************************
1210  * This function decreases the refcount of all objects in the list and
1211  * frees the list.
1212  *****************************************************************************/
1213 void vlc_list_release( vlc_list_t *p_list )
1214 {
1215     int i_index;
1216
1217     vlc_mutex_lock( &structure_lock );
1218     for( i_index = 0; i_index < p_list->i_count; i_index++ )
1219     {
1220         Release( p_list->p_values[i_index].p_object );
1221     }
1222     vlc_mutex_unlock( &structure_lock );
1223
1224     free( p_list->p_values );
1225     free( p_list );
1226 }
1227
1228 /* Following functions are local */
1229
1230 /*****************************************************************************
1231  * FindIndex: find the index of an object in an array of objects
1232  *****************************************************************************
1233  * This function assumes that p_this can be found in pp_objects. It will not
1234  * crash if p_this cannot be found, but will return a wrong value. It is your
1235  * duty to check the return value if you are not certain that the object could
1236  * be found for sure.
1237  *****************************************************************************/
1238 static int FindIndex( vlc_object_t *p_this,
1239                       vlc_object_t **pp_objects, int i_count )
1240 {
1241     int i_middle = i_count / 2;
1242
1243     if( i_count == 0 )
1244     {
1245         return 0;
1246     }
1247
1248     if( pp_objects[i_middle] == p_this )
1249     {
1250         return i_middle;
1251     }
1252
1253     if( i_count == 1 )
1254     {
1255         return 0;
1256     }
1257
1258     /* We take advantage of the sorted array */
1259     if( pp_objects[i_middle]->i_object_id < p_this->i_object_id )
1260     {
1261         return i_middle + FindIndex( p_this, pp_objects + i_middle,
1262                                              i_count - i_middle );
1263     }
1264     else
1265     {
1266         return FindIndex( p_this, pp_objects, i_middle );
1267     }
1268 }
1269
1270 static vlc_object_t * FindObject( vlc_object_t *p_this, int i_type, int i_mode )
1271 {
1272     int i;
1273     vlc_object_t *p_tmp;
1274
1275     switch( i_mode & 0x000f )
1276     {
1277     case FIND_PARENT:
1278         p_tmp = p_this->p_parent;
1279         if( p_tmp )
1280         {
1281             if( p_tmp->i_object_type == i_type )
1282             {
1283                 p_tmp->p_internals->i_refcount++;
1284                 return p_tmp;
1285             }
1286             else
1287             {
1288                 return FindObject( p_tmp, i_type, i_mode );
1289             }
1290         }
1291         break;
1292
1293     case FIND_CHILD:
1294         for( i = p_this->i_children; i--; )
1295         {
1296             p_tmp = p_this->pp_children[i];
1297             if( p_tmp->i_object_type == i_type )
1298             {
1299                 p_tmp->p_internals->i_refcount++;
1300                 return p_tmp;
1301             }
1302             else if( p_tmp->i_children )
1303             {
1304                 p_tmp = FindObject( p_tmp, i_type, i_mode );
1305                 if( p_tmp )
1306                 {
1307                     return p_tmp;
1308                 }
1309             }
1310         }
1311         break;
1312
1313     case FIND_ANYWHERE:
1314         /* Handled in vlc_object_find */
1315         break;
1316     }
1317
1318     return NULL;
1319 }
1320
1321 static vlc_object_t * FindObjectName( vlc_object_t *p_this,
1322                                       const char *psz_name,
1323                                       int i_mode )
1324 {
1325     int i;
1326     vlc_object_t *p_tmp;
1327
1328     switch( i_mode & 0x000f )
1329     {
1330     case FIND_PARENT:
1331         p_tmp = p_this->p_parent;
1332         if( p_tmp )
1333         {
1334             if( p_tmp->psz_object_name
1335                 && !strcmp( p_tmp->psz_object_name, psz_name ) )
1336             {
1337                 p_tmp->p_internals->i_refcount++;
1338                 return p_tmp;
1339             }
1340             else
1341             {
1342                 return FindObjectName( p_tmp, psz_name, i_mode );
1343             }
1344         }
1345         break;
1346
1347     case FIND_CHILD:
1348         for( i = p_this->i_children; i--; )
1349         {
1350             p_tmp = p_this->pp_children[i];
1351             if( p_tmp->psz_object_name
1352                 && !strcmp( p_tmp->psz_object_name, psz_name ) )
1353             {
1354                 p_tmp->p_internals->i_refcount++;
1355                 return p_tmp;
1356             }
1357             else if( p_tmp->i_children )
1358             {
1359                 p_tmp = FindObjectName( p_tmp, psz_name, i_mode );
1360                 if( p_tmp )
1361                 {
1362                     return p_tmp;
1363                 }
1364             }
1365         }
1366         break;
1367
1368     case FIND_ANYWHERE:
1369         /* Handled in vlc_object_find */
1370         break;
1371     }
1372
1373     return NULL;
1374 }
1375
1376 static void DetachObject( vlc_object_t *p_this )
1377 {
1378     vlc_object_t *p_parent = p_this->p_parent;
1379     int i_index, i;
1380
1381     /* Remove p_this's parent */
1382     p_this->p_parent = NULL;
1383
1384     /* Remove all of p_parent's children which are p_this */
1385     for( i_index = p_parent->i_children ; i_index-- ; )
1386     {
1387         if( p_parent->pp_children[i_index] == p_this )
1388         {
1389             p_parent->i_children--;
1390             for( i = i_index ; i < p_parent->i_children ; i++ )
1391             {
1392                 p_parent->pp_children[i] = p_parent->pp_children[i+1];
1393             }
1394         }
1395     }
1396
1397     if( p_parent->i_children )
1398     {
1399         p_parent->pp_children = (vlc_object_t **)realloc( p_parent->pp_children,
1400                                p_parent->i_children * sizeof(vlc_object_t *) );
1401     }
1402     else
1403     {
1404         free( p_parent->pp_children );
1405         p_parent->pp_children = NULL;
1406     }
1407 }
1408
1409 /*****************************************************************************
1410  * SetAttachment: recursively set the b_attached flag of a subtree.
1411  *****************************************************************************
1412  * This function is used by the attach and detach functions to propagate
1413  * the b_attached flag in a subtree.
1414  *****************************************************************************/
1415 static void SetAttachment( vlc_object_t *p_this, vlc_bool_t b_attached )
1416 {
1417     int i_index;
1418
1419     for( i_index = p_this->i_children ; i_index-- ; )
1420     {
1421         SetAttachment( p_this->pp_children[i_index], b_attached );
1422     }
1423
1424     p_this->p_internals->b_attached = b_attached;
1425 }
1426
1427 static void PrintObject( vlc_object_t *p_this, const char *psz_prefix )
1428 {
1429     char psz_children[20], psz_refcount[20], psz_thread[30], psz_name[50],
1430          psz_parent[20];
1431
1432     psz_name[0] = '\0';
1433     if( p_this->psz_object_name )
1434     {
1435         snprintf( psz_name, 49, " \"%s\"", p_this->psz_object_name );
1436         if( psz_name[48] )
1437             psz_name[48] = '\"';
1438     }
1439
1440     psz_children[0] = '\0';
1441     switch( p_this->i_children )
1442     {
1443         case 0:
1444             break;
1445         case 1:
1446             strcpy( psz_children, ", 1 child" );
1447             break;
1448         default:
1449             snprintf( psz_children, 19, ", %i children", p_this->i_children );
1450             break;
1451     }
1452
1453     psz_refcount[0] = '\0';
1454     if( p_this->p_internals->i_refcount > 0 )
1455         snprintf( psz_refcount, 19, ", refcount %u",
1456                   p_this->p_internals->i_refcount );
1457
1458     psz_thread[0] = '\0';
1459     if( p_this->p_internals->b_thread )
1460         snprintf( psz_thread, 29, " (thread %u)",
1461 #if defined(WIN32) || defined(UNDER_CE)
1462                   (unsigned)p_this->p_internals->thread_id.id );
1463 #else
1464                   (unsigned)p_this->p_internals->thread_id );
1465 #endif
1466
1467     psz_parent[0] = '\0';
1468     if( p_this->p_parent )
1469         snprintf( psz_parent, 19, ", parent %i", p_this->p_parent->i_object_id );
1470
1471     printf( " %so %.8i %s%s%s%s%s%s\n", psz_prefix,
1472             p_this->i_object_id, p_this->psz_object_type,
1473             psz_name, psz_thread, psz_refcount, psz_children,
1474             psz_parent );
1475 }
1476
1477 static void DumpStructure( vlc_object_t *p_this, int i_level, char *psz_foo )
1478 {
1479     int i;
1480     char i_back = psz_foo[i_level];
1481     psz_foo[i_level] = '\0';
1482
1483     PrintObject( p_this, psz_foo );
1484
1485     psz_foo[i_level] = i_back;
1486
1487     if( i_level / 2 >= MAX_DUMPSTRUCTURE_DEPTH )
1488     {
1489         msg_Warn( p_this, "structure tree is too deep" );
1490         return;
1491     }
1492
1493     for( i = 0 ; i < p_this->i_children ; i++ )
1494     {
1495         if( i_level )
1496         {
1497             psz_foo[i_level-1] = ' ';
1498
1499             if( psz_foo[i_level-2] == '`' )
1500             {
1501                 psz_foo[i_level-2] = ' ';
1502             }
1503         }
1504
1505         if( i == p_this->i_children - 1 )
1506         {
1507             psz_foo[i_level] = '`';
1508         }
1509         else
1510         {
1511             psz_foo[i_level] = '|';
1512         }
1513
1514         psz_foo[i_level+1] = '-';
1515         psz_foo[i_level+2] = '\0';
1516
1517         DumpStructure( p_this->pp_children[i], i_level + 2, psz_foo );
1518     }
1519 }
1520
1521 static vlc_list_t * NewList( int i_count )
1522 {
1523     vlc_list_t * p_list = (vlc_list_t *)malloc( sizeof( vlc_list_t ) );
1524     if( p_list == NULL )
1525     {
1526         return NULL;
1527     }
1528
1529     p_list->i_count = i_count;
1530
1531     if( i_count == 0 )
1532     {
1533         p_list->p_values = NULL;
1534         return p_list;
1535     }
1536
1537     p_list->p_values = malloc( i_count * sizeof( vlc_value_t ) );
1538     if( p_list->p_values == NULL )
1539     {
1540         p_list->i_count = 0;
1541         return p_list;
1542     }
1543
1544     return p_list;
1545 }
1546
1547 static void ListReplace( vlc_list_t *p_list, vlc_object_t *p_object,
1548                          int i_index )
1549 {
1550     if( p_list == NULL || i_index >= p_list->i_count )
1551     {
1552         return;
1553     }
1554
1555     p_object->p_internals->i_refcount++;
1556
1557     p_list->p_values[i_index].p_object = p_object;
1558
1559     return;
1560 }
1561
1562 /*static void ListAppend( vlc_list_t *p_list, vlc_object_t *p_object )
1563 {
1564     if( p_list == NULL )
1565     {
1566         return;
1567     }
1568
1569     p_list->p_values = realloc( p_list->p_values, (p_list->i_count + 1)
1570                                 * sizeof( vlc_value_t ) );
1571     if( p_list->p_values == NULL )
1572     {
1573         p_list->i_count = 0;
1574         return;
1575     }
1576
1577     p_object->p_internals->i_refcount++;
1578
1579     p_list->p_values[p_list->i_count].p_object = p_object;
1580     p_list->i_count++;
1581
1582     return;
1583 }*/
1584
1585 static int CountChildren( vlc_object_t *p_this, int i_type )
1586 {
1587     vlc_object_t *p_tmp;
1588     int i, i_count = 0;
1589
1590     for( i = 0; i < p_this->i_children; i++ )
1591     {
1592         p_tmp = p_this->pp_children[i];
1593
1594         if( p_tmp->i_object_type == i_type )
1595         {
1596             i_count++;
1597         }
1598
1599         if( p_tmp->i_children )
1600         {
1601             i_count += CountChildren( p_tmp, i_type );
1602         }
1603     }
1604
1605     return i_count;
1606 }
1607
1608 static void ListChildren( vlc_list_t *p_list, vlc_object_t *p_this, int i_type )
1609 {
1610     vlc_object_t *p_tmp;
1611     int i;
1612
1613     for( i = 0; i < p_this->i_children; i++ )
1614     {
1615         p_tmp = p_this->pp_children[i];
1616
1617         if( p_tmp->i_object_type == i_type )
1618         {
1619             ListReplace( p_list, p_tmp, p_list->i_count++ );
1620         }
1621
1622         if( p_tmp->i_children )
1623         {
1624             ListChildren( p_list, p_tmp, i_type );
1625         }
1626     }
1627 }