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