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