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