]> git.sesse.net Git - vlc/blob - src/misc/objects.c
Added some Doxygen doc
[vlc] / src / misc / objects.c
1 /*****************************************************************************
2  * objects.c: vlc_object_t handling
3  *****************************************************************************
4  * Copyright (C) 2002 VideoLAN
5  * $Id: objects.c,v 1.39 2003/09/18 17:54:02 zorglub Exp $
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., 59 Temple Place - Suite 330, Boston, MA  02111, 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 #ifdef HAVE_STDLIB_H
36 #   include <stdlib.h>                                          /* realloc() */
37 #endif
38
39 #include "stream_control.h"
40 #include "input_ext-intf.h"
41 #include "input_ext-dec.h"
42
43 #include "vlc_video.h"
44 #include "video_output.h"
45
46 #include "audio_output.h"
47 #include "aout_internal.h"
48 #include "stream_output.h"
49
50 #include "vlc_playlist.h"
51 #include "vlc_interface.h"
52
53 #include "httpd.h"
54 /*****************************************************************************
55  * Local prototypes
56  *****************************************************************************/
57 static int  DumpCommand( vlc_object_t *, char const *,
58                          vlc_value_t, vlc_value_t, void * );
59
60 static vlc_object_t * FindObject    ( vlc_object_t *, int, int );
61 static void           DetachObject  ( vlc_object_t * );
62 static void           PrintObject   ( vlc_object_t *, const char * );
63 static void           DumpStructure ( vlc_object_t *, int, char * );
64 static int            FindIndex     ( vlc_object_t *, vlc_object_t **, int );
65 static void           SetAttachment ( vlc_object_t *, vlc_bool_t );
66
67 static vlc_list_t   * NewList       ( int );
68 static void           ListReplace   ( vlc_list_t *, vlc_object_t *, int );
69 static void           ListAppend    ( vlc_list_t *, vlc_object_t * );
70 static int            CountChildren ( vlc_object_t *, int );
71 static void           ListChildren  ( vlc_list_t *, vlc_object_t *, int );
72
73 /*****************************************************************************
74  * Local structure lock
75  *****************************************************************************/
76 static vlc_mutex_t    structure_lock;
77
78 /*****************************************************************************
79  * vlc_object_create: initialize a vlc object
80  *****************************************************************************
81  * This function allocates memory for a vlc object and initializes it. If
82  * i_type is not a known value such as VLC_OBJECT_ROOT, VLC_OBJECT_VOUT and
83  * so on, vlc_object_create will use its value for the object size.
84  *****************************************************************************/
85
86 /** 
87  * Initialize a vlc object
88  *
89  * This function allocates memory for a vlc object and initializes it. If
90  * i_type is not a known value such as VLC_OBJECT_ROOT, VLC_OBJECT_VOUT and
91  * so on, vlc_object_create will use its value for the object size.
92  */
93 void * __vlc_object_create( vlc_object_t *p_this, int i_type )
94 {
95     vlc_object_t * p_new;
96     char *         psz_type;
97     size_t         i_size;
98
99     switch( i_type )
100     {
101         case VLC_OBJECT_ROOT:
102             i_size = sizeof(libvlc_t);
103             psz_type = "root";
104             break;
105         case VLC_OBJECT_VLC:
106             i_size = sizeof(vlc_t);
107             psz_type = "vlc";
108             break;
109         case VLC_OBJECT_MODULE:
110             i_size = sizeof(module_t);
111             psz_type = "module";
112             break;
113         case VLC_OBJECT_INTF:
114             i_size = sizeof(intf_thread_t);
115             psz_type = "interface";
116             break;
117         case VLC_OBJECT_PLAYLIST:
118             i_size = sizeof(playlist_t);
119             psz_type = "playlist";
120             break;
121         case VLC_OBJECT_INPUT:
122             i_size = sizeof(input_thread_t);
123             psz_type = "input";
124             break;
125         case VLC_OBJECT_DECODER:
126             i_size = sizeof(decoder_t);
127             psz_type = "decoder";
128             break;
129         case VLC_OBJECT_DECODER_FIFO: /* tmp for backward compat */
130             i_size = sizeof(decoder_fifo_t);
131             psz_type = "decoder";
132             break;
133         case VLC_OBJECT_VOUT:
134             i_size = sizeof(vout_thread_t);
135             psz_type = "video output";
136             break;
137         case VLC_OBJECT_AOUT:
138             i_size = sizeof(aout_instance_t);
139             psz_type = "audio output";
140             break;
141         case VLC_OBJECT_SOUT:
142             i_size = sizeof(sout_instance_t);
143             psz_type = "stream output";
144             break;
145         case VLC_OBJECT_HTTPD:
146             i_size = sizeof( httpd_t );
147             psz_type = "http daemon";
148             break;
149         default:
150             i_size = i_type > 0
151                       ? i_type > (int)sizeof(vlc_object_t)
152                          ? i_type : (int)sizeof(vlc_object_t)
153                       : (int)sizeof(vlc_object_t);
154             i_type = VLC_OBJECT_GENERIC;
155             psz_type = "generic";
156             break;
157     }
158
159     if( i_type == VLC_OBJECT_ROOT )
160     {
161         p_new = p_this;
162     }
163     else
164     {
165         p_new = malloc( i_size );
166
167         if( !p_new )
168         {
169             return NULL;
170         }
171
172         memset( p_new, 0, i_size );
173     }
174
175     p_new->i_object_type = i_type;
176     p_new->psz_object_type = psz_type;
177
178     p_new->psz_object_name = NULL;
179
180     p_new->b_die = VLC_FALSE;
181     p_new->b_error = VLC_FALSE;
182     p_new->b_dead = VLC_FALSE;
183     p_new->b_attached = VLC_FALSE;
184
185     p_new->i_vars = 0;
186     p_new->p_vars = (variable_t *)malloc( 16 * sizeof( variable_t ) );
187
188     if( !p_new->p_vars )
189     {
190         free( p_new );
191         return NULL;
192     }
193
194     if( i_type == VLC_OBJECT_ROOT )
195     {
196         /* If i_type is root, then p_new is actually p_libvlc */
197         p_new->p_libvlc = (libvlc_t*)p_new;
198         p_new->p_vlc = NULL;
199
200         p_new->p_libvlc->i_counter = 0;
201         p_new->i_object_id = 0;
202
203         p_new->p_libvlc->i_objects = 1;
204         p_new->p_libvlc->pp_objects = malloc( sizeof(vlc_object_t *) );
205         p_new->p_libvlc->pp_objects[0] = p_new;
206         p_new->b_attached = VLC_TRUE;
207     }
208     else
209     {
210         p_new->p_libvlc = p_this->p_libvlc;
211         p_new->p_vlc = ( i_type == VLC_OBJECT_VLC ) ? (vlc_t*)p_new
212                                                     : p_this->p_vlc;
213
214         vlc_mutex_lock( &structure_lock );
215
216         p_new->p_libvlc->i_counter++;
217         p_new->i_object_id = p_new->p_libvlc->i_counter;
218
219         /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
220          * useless to try and recover anything if pp_objects gets smashed. */
221         INSERT_ELEM( p_new->p_libvlc->pp_objects,
222                      p_new->p_libvlc->i_objects,
223                      p_new->p_libvlc->i_objects,
224                      p_new );
225
226         vlc_mutex_unlock( &structure_lock );
227     }
228
229     p_new->i_refcount = 0;
230     p_new->p_parent = NULL;
231     p_new->pp_children = NULL;
232     p_new->i_children = 0;
233
234     p_new->p_private = NULL;
235
236     /* Initialize mutexes and condvars */
237     vlc_mutex_init( p_new, &p_new->object_lock );
238     vlc_cond_init( p_new, &p_new->object_wait );
239     vlc_mutex_init( p_new, &p_new->var_lock );
240
241     if( i_type == VLC_OBJECT_ROOT )
242     {
243         vlc_mutex_init( p_new, &structure_lock );
244
245         var_Create( p_new, "list", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
246         var_AddCallback( p_new, "list", DumpCommand, NULL );
247         var_Create( p_new, "tree", VLC_VAR_STRING | VLC_VAR_ISCOMMAND );
248         var_AddCallback( p_new, "tree", DumpCommand, NULL );
249     }
250
251     return p_new;
252 }
253
254 /**
255  ****************************************************************************
256  * Destroy a vlc object
257  * 
258  * This function destroys an object that has been previously allocated with
259  * vlc_object_create. The object's refcount must be zero and it must not be
260  * attached to other objects in any way.
261  *****************************************************************************/
262 void __vlc_object_destroy( vlc_object_t *p_this )
263 {
264     int i_delay = 0;
265
266     if( p_this->i_children )
267     {
268         msg_Err( p_this, "cannot delete object with children" );
269         return;
270     }
271
272     if( p_this->p_parent )
273     {
274         msg_Err( p_this, "cannot delete object with a parent" );
275         return;
276     }
277
278     while( p_this->i_refcount )
279     {
280         i_delay++;
281
282         /* Don't warn immediately ... 100ms seems OK */
283         if( i_delay == 2 )
284         {
285             msg_Warn( p_this, "refcount is %i, delaying before deletion",
286                               p_this->i_refcount );
287         }
288         else if( i_delay == 12 )
289         {
290             msg_Err( p_this, "refcount is %i, I have a bad feeling about this",
291                              p_this->i_refcount );
292         }
293         else if( i_delay == 42 )
294         {
295             msg_Err( p_this, "we waited too long, cancelling destruction" );
296             return;
297         }
298
299         msleep( 100000 );
300     }
301
302     /* Destroy the associated variables, starting from the end so that
303      * no memmove calls have to be done. */
304     while( p_this->i_vars )
305     {
306         var_Destroy( p_this, p_this->p_vars[p_this->i_vars - 1].psz_name );
307     }
308
309     free( p_this->p_vars );
310     vlc_mutex_destroy( &p_this->var_lock );
311
312     if( p_this->i_object_type == VLC_OBJECT_ROOT )
313     {
314         /* We are the root object ... no need to lock. */
315         free( p_this->p_libvlc->pp_objects );
316         p_this->p_libvlc->pp_objects = NULL;
317         p_this->p_libvlc->i_objects--;
318
319         vlc_mutex_destroy( &structure_lock );
320     }
321     else
322     {
323         int i_index;
324
325         vlc_mutex_lock( &structure_lock );
326
327         /* Wooohaa! If *this* fails, we're in serious trouble! Anyway it's
328          * useless to try and recover anything if pp_objects gets smashed. */
329         i_index = FindIndex( p_this, p_this->p_libvlc->pp_objects,
330                              p_this->p_libvlc->i_objects );
331         REMOVE_ELEM( p_this->p_libvlc->pp_objects,
332                      p_this->p_libvlc->i_objects, i_index );
333
334         vlc_mutex_unlock( &structure_lock );
335     }
336
337     vlc_mutex_destroy( &p_this->object_lock );
338     vlc_cond_destroy( &p_this->object_wait );
339
340     free( p_this );
341 }
342
343 /**
344  * find an object given its ID
345  *
346  * This function looks for the object whose i_object_id field is i_id. We
347  * use a dichotomy so that lookups are in log2(n).
348  *****************************************************************************/
349 void * __vlc_object_get( vlc_object_t *p_this, int i_id )
350 {
351     int i_max, i_middle;
352     vlc_object_t **pp_objects;
353
354     vlc_mutex_lock( &structure_lock );
355
356     pp_objects = p_this->p_libvlc->pp_objects;
357
358     /* Perform our dichotomy */
359     for( i_max = p_this->p_libvlc->i_objects - 1 ; ; )
360     {
361         i_middle = i_max / 2;
362
363         if( pp_objects[i_middle]->i_object_id > i_id )
364         {
365             i_max = i_middle;
366         }
367         else if( pp_objects[i_middle]->i_object_id < i_id )
368         {
369             if( i_middle )
370             {
371                 pp_objects += i_middle;
372                 i_max -= i_middle;
373             }
374             else
375             {
376                 /* This happens when there are only two remaining objects */
377                 if( pp_objects[i_middle+1]->i_object_id == i_id )
378                 {
379                     vlc_mutex_unlock( &structure_lock );
380                     pp_objects[i_middle+1]->i_refcount++;
381                     return pp_objects[i_middle+1];
382                 }
383                 break;
384             }
385         }
386         else
387         {
388             vlc_mutex_unlock( &structure_lock );
389             pp_objects[i_middle]->i_refcount++;
390             return pp_objects[i_middle];
391         }
392
393         if( i_max == 0 )
394         {
395             /* this means that i_max == i_middle, and since we have already
396              * tested pp_objects[i_middle]), p_found is properly set. */
397             break;
398         }
399     }
400
401     vlc_mutex_unlock( &structure_lock );
402     return NULL;
403 }
404
405 /**
406  ****************************************************************************
407  * find a typed object and increment its refcount
408  *****************************************************************************
409  * This function recursively looks for a given object type. i_mode can be one
410  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
411  *****************************************************************************/
412 void * __vlc_object_find( vlc_object_t *p_this, int i_type, int i_mode )
413 {
414     vlc_object_t *p_found;
415
416     vlc_mutex_lock( &structure_lock );
417
418     /* If we are of the requested type ourselves, don't look further */
419     if( !(i_mode & FIND_STRICT) && p_this->i_object_type == i_type )
420     {
421         p_this->i_refcount++;
422         vlc_mutex_unlock( &structure_lock );
423         return p_this;
424     }
425
426     /* Otherwise, recursively look for the object */
427     if( (i_mode & 0x000f) == FIND_ANYWHERE )
428     {
429         p_found = FindObject( VLC_OBJECT(p_this->p_vlc), i_type,
430                               (i_mode & ~0x000f) | FIND_CHILD );
431     }
432     else
433     {
434         p_found = FindObject( p_this, i_type, i_mode );
435     }
436
437     vlc_mutex_unlock( &structure_lock );
438
439     return p_found;
440 }
441
442 /**
443  ****************************************************************************
444  * increment an object refcount
445  *****************************************************************************/
446 void __vlc_object_yield( vlc_object_t *p_this )
447 {
448     vlc_mutex_lock( &structure_lock );
449     p_this->i_refcount++;
450     vlc_mutex_unlock( &structure_lock );
451 }
452
453 /**
454  ****************************************************************************
455  * decrement an object refcount
456  *****************************************************************************/
457 void __vlc_object_release( vlc_object_t *p_this )
458 {
459     vlc_mutex_lock( &structure_lock );
460     p_this->i_refcount--;
461     vlc_mutex_unlock( &structure_lock );
462 }
463
464 /**
465  ****************************************************************************
466  * attach object to a parent object
467  *****************************************************************************
468  * This function sets p_this as a child of p_parent, and p_parent as a parent
469  * of p_this. This link can be undone using vlc_object_detach.
470  *****************************************************************************/
471 void __vlc_object_attach( vlc_object_t *p_this, vlc_object_t *p_parent )
472 {
473     vlc_mutex_lock( &structure_lock );
474
475     /* Attach the parent to its child */
476     p_this->p_parent = p_parent;
477
478     /* Attach the child to its parent */
479     INSERT_ELEM( p_parent->pp_children, p_parent->i_children,
480                  p_parent->i_children, p_this );
481
482     /* Climb up the tree to see whether we are connected with the root */
483     if( p_parent->b_attached )
484     {
485         SetAttachment( p_this, VLC_TRUE );
486     }
487
488     vlc_mutex_unlock( &structure_lock );
489 }
490
491 /**
492  ****************************************************************************
493  * detach object from its parent
494  *****************************************************************************
495  * This function removes all links between an object and its parent.
496  *****************************************************************************/
497 void __vlc_object_detach( vlc_object_t *p_this )
498 {
499     vlc_mutex_lock( &structure_lock );
500     if( !p_this->p_parent )
501     {
502         msg_Err( p_this, "object is not attached" );
503         vlc_mutex_unlock( &structure_lock );
504         return;
505     }
506
507     /* Climb up the tree to see whether we are connected with the root */
508     if( p_this->p_parent->b_attached )
509     {
510         SetAttachment( p_this, VLC_FALSE );
511     }
512
513     DetachObject( p_this );
514     vlc_mutex_unlock( &structure_lock );
515 }
516
517 /**
518  ****************************************************************************
519  * find a list typed objects and increment their refcount
520  *****************************************************************************
521  * This function recursively looks for a given object type. i_mode can be one
522  * of FIND_PARENT, FIND_CHILD or FIND_ANYWHERE.
523  *****************************************************************************/
524 vlc_list_t * __vlc_list_find( vlc_object_t *p_this, int i_type, int i_mode )
525 {
526     vlc_list_t *p_list;
527     vlc_object_t **pp_current, **pp_end;
528     int i_count = 0, i_index = 0;
529
530     vlc_mutex_lock( &structure_lock );
531
532     /* Look for the objects */
533     switch( i_mode & 0x000f )
534     {
535     case FIND_ANYWHERE:
536         pp_current = p_this->p_libvlc->pp_objects;
537         pp_end = pp_current + p_this->p_libvlc->i_objects;
538
539         for( ; pp_current < pp_end ; pp_current++ )
540         {
541             if( (*pp_current)->b_attached
542                  && (*pp_current)->i_object_type == i_type )
543             {
544                 i_count++;
545             }
546         }
547
548         p_list = NewList( i_count );
549         pp_current = p_this->p_libvlc->pp_objects;
550
551         for( ; pp_current < pp_end ; pp_current++ )
552         {
553             if( (*pp_current)->b_attached
554                  && (*pp_current)->i_object_type == i_type )
555             {
556                 ListReplace( p_list, *pp_current, i_index );
557                 if( i_index < i_count ) i_index++;
558             }
559         }
560     break;
561
562     case FIND_CHILD:
563         i_count = CountChildren( p_this, i_type );
564         p_list = NewList( i_count );
565
566         /* Check allocation was successful */
567         if( p_list->i_count != i_count )
568         {
569             msg_Err( p_this, "list allocation failed!" );
570             p_list->i_count = 0;
571             break;
572         }
573
574         p_list->i_count = 0;
575         ListChildren( p_list, p_this, i_type );
576         break;
577
578     default:
579         msg_Err( p_this, "unimplemented!" );
580         p_list = NewList( 0 );
581         break;
582     }
583
584     vlc_mutex_unlock( &structure_lock );
585
586     return p_list;
587 }
588
589 /*****************************************************************************
590  * DumpCommand: print the current vlc structure
591  *****************************************************************************
592  * This function prints either an ASCII tree showing the connections between
593  * vlc objects, and additional information such as their refcount, thread ID,
594  * etc. (command "tree"), or the same data as a simple list (command "list").
595  *****************************************************************************/
596 static int DumpCommand( vlc_object_t *p_this, char const *psz_cmd,
597                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
598 {
599     if( *psz_cmd == 't' )
600     {
601         char psz_foo[2 * MAX_DUMPSTRUCTURE_DEPTH + 1];
602         vlc_object_t *p_object;
603
604         if( *newval.psz_string )
605         {
606             p_object = vlc_object_get( p_this, atoi(newval.psz_string) );
607
608             if( !p_object )
609             {
610                 return VLC_ENOOBJ;
611             }
612         }
613         else
614         {
615             p_object = p_this->p_vlc ? VLC_OBJECT(p_this->p_vlc) : p_this;
616         }
617
618         vlc_mutex_lock( &structure_lock );
619
620         psz_foo[0] = '|';
621         DumpStructure( p_object, 0, psz_foo );
622
623         vlc_mutex_unlock( &structure_lock );
624
625         if( *newval.psz_string )
626         {
627             vlc_object_release( p_this );
628         }
629     }
630     else if( *psz_cmd == 'l' )
631     {
632         vlc_object_t **pp_current, **pp_end;
633
634         vlc_mutex_lock( &structure_lock );
635
636         pp_current = p_this->p_libvlc->pp_objects;
637         pp_end = pp_current + p_this->p_libvlc->i_objects;
638
639         for( ; pp_current < pp_end ; pp_current++ )
640         {
641             if( (*pp_current)->b_attached )
642             {
643                 PrintObject( *pp_current, "" );
644             }
645             else
646             {
647                 printf( " o %.8i %s (not attached)\n",
648                         (*pp_current)->i_object_id,
649                         (*pp_current)->psz_object_type );
650             }
651         }
652
653         vlc_mutex_unlock( &structure_lock );
654     }
655
656     return VLC_SUCCESS;
657 }
658
659 /*****************************************************************************
660  * vlc_list_release: free a list previously allocated by vlc_list_find
661  *****************************************************************************
662  * This function decreases the refcount of all objects in the list and
663  * frees the list.
664  *****************************************************************************/
665 void vlc_list_release( vlc_list_t *p_list )
666 {
667     int i_index;
668
669     for( i_index = 0; i_index < p_list->i_count; i_index++ )
670     {
671         vlc_mutex_lock( &structure_lock );
672
673         p_list->p_values[i_index].p_object->i_refcount--;
674
675         vlc_mutex_unlock( &structure_lock );
676     }
677
678     free( p_list->p_values );
679     free( p_list );
680 }
681
682 /* Following functions are local */
683
684 /*****************************************************************************
685  * FindIndex: find the index of an object in an array of objects
686  *****************************************************************************
687  * This function assumes that p_this can be found in pp_objects. It will not
688  * crash if p_this cannot be found, but will return a wrong value. It is your
689  * duty to check the return value if you are not certain that the object could
690  * be found for sure.
691  *****************************************************************************/
692 static int FindIndex( vlc_object_t *p_this,
693                       vlc_object_t **pp_objects, int i_count )
694 {
695     int i_middle = i_count / 2;
696
697     if( i_count == 0 )
698     {
699         return 0;
700     }
701
702     if( pp_objects[i_middle] == p_this )
703     {
704         return i_middle;
705     }
706
707     if( i_count == 1 )
708     {
709         return 0;
710     }
711
712     /* We take advantage of the sorted array */
713     if( pp_objects[i_middle]->i_object_id < p_this->i_object_id )
714     {
715         return i_middle + FindIndex( p_this, pp_objects + i_middle,
716                                              i_count - i_middle );
717     }
718     else
719     {
720         return FindIndex( p_this, pp_objects, i_middle );
721     }
722 }
723
724 static vlc_object_t * FindObject( vlc_object_t *p_this, int i_type, int i_mode )
725 {
726     int i;
727     vlc_object_t *p_tmp;
728
729     switch( i_mode & 0x000f )
730     {
731     case FIND_PARENT:
732         p_tmp = p_this->p_parent;
733         if( p_tmp )
734         {
735             if( p_tmp->i_object_type == i_type )
736             {
737                 p_tmp->i_refcount++;
738                 return p_tmp;
739             }
740             else
741             {
742                 return FindObject( p_tmp, i_type, i_mode );
743             }
744         }
745         break;
746
747     case FIND_CHILD:
748         for( i = p_this->i_children; i--; )
749         {
750             p_tmp = p_this->pp_children[i];
751             if( p_tmp->i_object_type == i_type )
752             {
753                 p_tmp->i_refcount++;
754                 return p_tmp;
755             }
756             else if( p_tmp->i_children )
757             {
758                 p_tmp = FindObject( p_tmp, i_type, i_mode );
759                 if( p_tmp )
760                 {
761                     return p_tmp;
762                 }
763             }
764         }
765         break;
766
767     case FIND_ANYWHERE:
768         /* Handled in vlc_object_find */
769         break;
770     }
771
772     return NULL;
773 }
774
775 static void DetachObject( vlc_object_t *p_this )
776 {
777     vlc_object_t *p_parent = p_this->p_parent;
778     int i_index, i;
779
780     /* Remove p_this's parent */
781     p_this->p_parent = NULL;
782
783     /* Remove all of p_parent's children which are p_this */
784     for( i_index = p_parent->i_children ; i_index-- ; )
785     {
786         if( p_parent->pp_children[i_index] == p_this )
787         {
788             p_parent->i_children--;
789             for( i = i_index ; i < p_parent->i_children ; i++ )
790             {
791                 p_parent->pp_children[i] = p_parent->pp_children[i+1];
792             }
793         }
794     }
795
796     if( p_parent->i_children )
797     {
798         p_parent->pp_children = (vlc_object_t **)realloc( p_parent->pp_children,
799                                p_parent->i_children * sizeof(vlc_object_t *) );
800     }
801     else
802     {
803         free( p_parent->pp_children );
804         p_parent->pp_children = NULL;
805     }
806 }
807
808 /*****************************************************************************
809  * SetAttachment: recursively set the b_attached flag of a subtree.
810  *****************************************************************************
811  * This function is used by the attach and detach functions to propagate
812  * the b_attached flag in a subtree.
813  *****************************************************************************/
814 static void SetAttachment( vlc_object_t *p_this, vlc_bool_t b_attached )
815 {
816     int i_index;
817
818     for( i_index = p_this->i_children ; i_index-- ; )
819     {
820         SetAttachment( p_this->pp_children[i_index], b_attached );
821     }
822
823     p_this->b_attached = b_attached;
824 }
825
826 static void PrintObject( vlc_object_t *p_this, const char *psz_prefix )
827 {
828     char psz_children[20], psz_refcount[20], psz_thread[20], psz_name[50];
829
830     psz_name[0] = '\0';
831     if( p_this->psz_object_name )
832     {
833         snprintf( psz_name, 50, " \"%s\"", p_this->psz_object_name );
834         psz_name[48] = '\"';
835         psz_name[49] = '\0';
836     }
837
838     psz_children[0] = '\0';
839     switch( p_this->i_children )
840     {
841         case 0:
842             break;
843         case 1:
844             strcpy( psz_children, ", 1 child" );
845             break;
846         default:
847             snprintf( psz_children, 20,
848                       ", %i children", p_this->i_children );
849             psz_children[19] = '\0';
850             break;
851     }
852
853     psz_refcount[0] = '\0';
854     if( p_this->i_refcount )
855     {
856         snprintf( psz_refcount, 20, ", refcount %i", p_this->i_refcount );
857         psz_refcount[19] = '\0';
858     }
859
860     psz_thread[0] = '\0';
861     if( p_this->b_thread )
862     {
863         snprintf( psz_thread, 20, " (thread %d)", (int)p_this->thread_id );
864         psz_thread[19] = '\0';
865     }
866
867     printf( " %so %.8i %s%s%s%s%s\n", psz_prefix,
868             p_this->i_object_id, p_this->psz_object_type,
869             psz_name, psz_thread, psz_refcount, psz_children );
870 }
871
872 static void DumpStructure( vlc_object_t *p_this, int i_level, char *psz_foo )
873 {
874     int i;
875     char i_back = psz_foo[i_level];
876     psz_foo[i_level] = '\0';
877
878     PrintObject( p_this, psz_foo );
879
880     psz_foo[i_level] = i_back;
881
882     if( i_level / 2 >= MAX_DUMPSTRUCTURE_DEPTH )
883     {
884         msg_Warn( p_this, "structure tree is too deep" );
885         return;
886     }
887
888     for( i = 0 ; i < p_this->i_children ; i++ )
889     {
890         if( i_level )
891         {
892             psz_foo[i_level-1] = ' ';
893
894             if( psz_foo[i_level-2] == '`' )
895             {
896                 psz_foo[i_level-2] = ' ';
897             }
898         }
899
900         if( i == p_this->i_children - 1 )
901         {
902             psz_foo[i_level] = '`';
903         }
904         else
905         {
906             psz_foo[i_level] = '|';
907         }
908
909         psz_foo[i_level+1] = '-';
910         psz_foo[i_level+2] = '\0';
911
912         DumpStructure( p_this->pp_children[i], i_level + 2, psz_foo );
913     }
914 }
915
916 static vlc_list_t * NewList( int i_count )
917 {
918     vlc_list_t * p_list = (vlc_list_t *)malloc( sizeof( vlc_list_t ) );
919     if( p_list == NULL )
920     {
921         return NULL;
922     }
923
924     p_list->i_count = i_count;
925
926     if( i_count == 0 )
927     {
928         p_list->p_values = NULL;
929         return p_list;
930     }
931
932     p_list->p_values = malloc( i_count * sizeof( vlc_value_t ) );
933     if( p_list->p_values == NULL )
934     {
935         p_list->i_count = 0;
936         return p_list;
937     }
938
939     return p_list;
940 }
941
942 static void ListReplace( vlc_list_t *p_list, vlc_object_t *p_object,
943                          int i_index )
944 {
945     if( p_list == NULL || i_index >= p_list->i_count )
946     {
947         return;
948     }
949
950     p_object->i_refcount++;
951
952     p_list->p_values[i_index].p_object = p_object;
953
954     return;
955 }
956
957 static void ListAppend( vlc_list_t *p_list, vlc_object_t *p_object )
958 {
959     if( p_list == NULL )
960     {
961         return;
962     }
963
964     p_list->p_values = realloc( p_list->p_values, (p_list->i_count + 1)
965                                 * sizeof( vlc_value_t ) );
966     if( p_list->p_values == NULL )
967     {
968         p_list->i_count = 0;
969         return;
970     }
971
972     p_object->i_refcount++;
973
974     p_list->p_values[p_list->i_count].p_object = p_object;
975     p_list->i_count++;
976
977     return;
978 }
979
980 static int CountChildren( vlc_object_t *p_this, int i_type )
981 {
982     vlc_object_t *p_tmp;
983     int i, i_count = 0;
984
985     for( i = 0; i < p_this->i_children; i++ )
986     {
987         p_tmp = p_this->pp_children[i];
988
989         if( p_tmp->i_object_type == i_type )
990         {
991             i_count++;
992         }
993
994         if( p_tmp->i_children )
995         {
996             i_count += CountChildren( p_tmp, i_type );
997         }
998     }
999
1000     return i_count;
1001 }
1002
1003 static void ListChildren( vlc_list_t *p_list, vlc_object_t *p_this, int i_type )
1004 {
1005     vlc_object_t *p_tmp;
1006     int i;
1007
1008     for( i = 0; i < p_this->i_children; i++ )
1009     {
1010         p_tmp = p_this->pp_children[i];
1011
1012         if( p_tmp->i_object_type == i_type )
1013         {
1014             ListReplace( p_list, p_tmp, p_list->i_count++ );
1015         }
1016
1017         if( p_tmp->i_children )
1018         {
1019             ListChildren( p_list, p_tmp, i_type );
1020         }
1021     }
1022 }