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