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