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