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