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