LGPL
[vlc.git] / src / misc / objects.c
1 /*****************************************************************************
2  * objects.c: vlc_object_t handling
3  *****************************************************************************
4  * Copyright (C) 2004-2008 VLC authors and VideoLAN
5  * Copyright (C) 2006-2010 RĂ©mi Denis-Courmont
6  *
7  * Authors: Samuel Hocevar <sam@zoy.org>
8  *
9  * This program is free software; you can redistribute it and/or modify it
10  * under the terms of the GNU Lesser General Public License as published by
11  * the Free Software Foundation; either version 2.1 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 Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public License
20  * along with this program; if not, write to the Free Software Foundation,
21  * 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  * Unless otherwise stated, functions in this file are not cancellation point.
29  * All functions in this file are safe w.r.t. deferred cancellation.
30  */
31
32
33 /*****************************************************************************
34  * Preamble
35  *****************************************************************************/
36 #ifdef HAVE_CONFIG_H
37 # include "config.h"
38 #endif
39
40 #include <vlc_common.h>
41
42 #include "../libvlc.h"
43 #include <vlc_aout.h>
44 #include "audio_output/aout_internal.h"
45
46 #include "vlc_interface.h"
47 #include "vlc_codec.h"
48
49 #include "variables.h"
50
51 #ifdef HAVE_SEARCH_H
52 # include <search.h>
53 #endif
54
55 #ifdef __OS2__
56 # include <sys/socket.h>
57 # include <netinet/in.h>
58 # include <unistd.h>    // close(), write()
59 #elif defined(WIN32)
60 # include <io.h>
61 # include <winsock2.h>
62 # include <ws2tcpip.h>
63 # undef  read
64 # define read( a, b, c )  recv (a, b, c, 0)
65 # undef  write
66 # define write( a, b, c ) send (a, b, c, 0)
67 # undef  close
68 # define close( a )       closesocket (a)
69 #else
70 # include <vlc_fs.h>
71 # include <unistd.h>
72 #endif
73
74 #include <limits.h>
75 #include <assert.h>
76
77 #if defined (HAVE_SYS_EVENTFD_H)
78 # include <sys/eventfd.h>
79 # ifndef EFD_CLOEXEC
80 #  define EFD_CLOEXEC 0
81 #  warning EFD_CLOEXEC missing. Consider updating libc.
82 # endif
83 #endif
84
85
86 /*****************************************************************************
87  * Local prototypes
88  *****************************************************************************/
89 static int  DumpCommand( vlc_object_t *, char const *,
90                          vlc_value_t, vlc_value_t, void * );
91
92 static vlc_object_t * FindName ( vlc_object_internals_t *, const char * );
93 static void PrintObject( vlc_object_internals_t *, const char * );
94 static void DumpStructure( vlc_object_internals_t *, unsigned, char * );
95
96 static vlc_list_t   * NewList       ( int );
97
98 static void vlc_object_destroy( vlc_object_t *p_this );
99
100 /*****************************************************************************
101  * Local structure lock
102  *****************************************************************************/
103 static void libvlc_lock (libvlc_int_t *p_libvlc)
104 {
105     vlc_mutex_lock (&(libvlc_priv (p_libvlc)->structure_lock));
106 }
107
108 static void libvlc_unlock (libvlc_int_t *p_libvlc)
109 {
110     vlc_mutex_unlock (&(libvlc_priv (p_libvlc)->structure_lock));
111 }
112
113 #undef vlc_custom_create
114 void *vlc_custom_create (vlc_object_t *parent, size_t length,
115                          const char *typename)
116 {
117     /* NOTE:
118      * VLC objects are laid out as follow:
119      * - first the LibVLC-private per-object data,
120      * - then VLC_COMMON members from vlc_object_t,
121      * - finally, the type-specific data (if any).
122      *
123      * This function initializes the LibVLC and common data,
124      * and zeroes the rest.
125      */
126     assert (length >= sizeof (vlc_object_t));
127
128     vlc_object_internals_t *priv = malloc (sizeof (*priv) + length);
129     if (unlikely(priv == NULL))
130         return NULL;
131     priv->psz_name = NULL;
132     priv->var_root = NULL;
133     vlc_mutex_init (&priv->var_lock);
134     vlc_cond_init (&priv->var_wait);
135     priv->pipes[0] = priv->pipes[1] = -1;
136     vlc_spin_init (&priv->ref_spin);
137     priv->i_refcount = 1;
138     priv->pf_destructor = NULL;
139     priv->prev = NULL;
140     priv->first = NULL;
141
142     vlc_object_t *obj = (vlc_object_t *)(priv + 1);
143     obj->psz_object_type = typename;
144     obj->psz_header = NULL;
145     obj->b_die = false;
146     obj->b_force = false;
147     memset (obj + 1, 0, length - sizeof (*obj)); /* type-specific stuff */
148
149     if (likely(parent != NULL))
150     {
151         vlc_object_internals_t *papriv = vlc_internals (parent);
152
153         obj->i_flags = parent->i_flags;
154         obj->p_libvlc = parent->p_libvlc;
155
156         /* Attach the child to its parent (no lock needed) */
157         obj->p_parent = vlc_object_hold (parent);
158
159         /* Attach the parent to its child (structure lock needed) */
160         libvlc_lock (obj->p_libvlc);
161         priv->next = papriv->first;
162         if (priv->next != NULL)
163             priv->next->prev = priv;
164         papriv->first = priv;
165         libvlc_unlock (obj->p_libvlc);
166     }
167     else
168     {
169         libvlc_int_t *self = (libvlc_int_t *)obj;
170
171         obj->i_flags = 0;
172         obj->p_libvlc = self;
173         obj->p_parent = NULL;
174         priv->next = NULL;
175         vlc_mutex_init (&(libvlc_priv (self)->structure_lock));
176
177         /* TODO: should be in src/libvlc.c */
178         int canc = vlc_savecancel ();
179         var_Create (obj, "tree", VLC_VAR_STRING | VLC_VAR_ISCOMMAND);
180         var_AddCallback (obj, "tree", DumpCommand, obj);
181         var_Create (obj, "vars", VLC_VAR_STRING | VLC_VAR_ISCOMMAND);
182         var_AddCallback (obj, "vars", DumpCommand, obj);
183         vlc_restorecancel (canc);
184     }
185
186     return obj;
187 }
188
189 #undef vlc_object_create
190 /**
191  * Allocates and initializes a vlc object.
192  *
193  * @param i_size object byte size
194  *
195  * @return the new object, or NULL on error.
196  */
197 void *vlc_object_create( vlc_object_t *p_this, size_t i_size )
198 {
199     return vlc_custom_create( p_this, i_size, "generic" );
200 }
201
202 #undef vlc_object_set_destructor
203 /**
204  ****************************************************************************
205  * Set the destructor of a vlc object
206  *
207  * This function sets the destructor of the vlc object. It will be called
208  * when the object is destroyed when the its refcount reaches 0.
209  * (It is called by the internal function vlc_object_destroy())
210  *****************************************************************************/
211 void vlc_object_set_destructor( vlc_object_t *p_this,
212                                 vlc_destructor_t pf_destructor )
213 {
214     vlc_object_internals_t *p_priv = vlc_internals(p_this );
215
216     vlc_spin_lock( &p_priv->ref_spin );
217     p_priv->pf_destructor = pf_destructor;
218     vlc_spin_unlock( &p_priv->ref_spin );
219 }
220
221 static vlc_mutex_t name_lock = VLC_STATIC_MUTEX;
222
223 #undef vlc_object_set_name
224 int vlc_object_set_name(vlc_object_t *obj, const char *name)
225 {
226     vlc_object_internals_t *priv = vlc_internals(obj);
227     char *newname = name ? strdup (name) : NULL;
228     char *oldname;
229
230     vlc_mutex_lock (&name_lock);
231     oldname = priv->psz_name;
232     priv->psz_name = newname;
233     vlc_mutex_unlock (&name_lock);
234
235     free (oldname);
236     return (priv->psz_name || !name) ? VLC_SUCCESS : VLC_ENOMEM;
237 }
238
239 #undef vlc_object_get_name
240 char *vlc_object_get_name(const vlc_object_t *obj)
241 {
242     vlc_object_internals_t *priv = vlc_internals(obj);
243     char *name;
244
245     vlc_mutex_lock (&name_lock);
246     name = priv->psz_name ? strdup (priv->psz_name) : NULL;
247     vlc_mutex_unlock (&name_lock);
248
249     return name;
250 }
251
252 /**
253  * Destroys a VLC object once it has no more references.
254  *
255  * This function must be called with cancellation disabled (currently).
256  */
257 static void vlc_object_destroy( vlc_object_t *p_this )
258 {
259     vlc_object_internals_t *p_priv = vlc_internals( p_this );
260
261     /* Call the custom "subclass" destructor */
262     if( p_priv->pf_destructor )
263         p_priv->pf_destructor( p_this );
264
265     if (unlikely(p_this == VLC_OBJECT(p_this->p_libvlc)))
266     {
267         /* TODO: should be in src/libvlc.c */
268         var_DelCallback (p_this, "tree", DumpCommand, p_this);
269         var_DelCallback (p_this, "vars", DumpCommand, p_this);
270     }
271
272     /* Destroy the associated variables. */
273     var_DestroyAll( p_this );
274
275     vlc_cond_destroy( &p_priv->var_wait );
276     vlc_mutex_destroy( &p_priv->var_lock );
277
278     free( p_this->psz_header );
279
280     free( p_priv->psz_name );
281
282     vlc_spin_destroy( &p_priv->ref_spin );
283     if( p_priv->pipes[1] != -1 && p_priv->pipes[1] != p_priv->pipes[0] )
284         close( p_priv->pipes[1] );
285     if( p_priv->pipes[0] != -1 )
286         close( p_priv->pipes[0] );
287     if( VLC_OBJECT(p_this->p_libvlc) == p_this )
288         vlc_mutex_destroy (&(libvlc_priv ((libvlc_int_t *)p_this)->structure_lock));
289
290     free( p_priv );
291 }
292
293
294 #if defined(WIN32) || defined(__OS2__)
295 /**
296  * select()-able pipes emulated using Winsock
297  */
298 # define vlc_pipe selectable_pipe
299 static int selectable_pipe (int fd[2])
300 {
301     struct sockaddr_in addr;
302     int addrlen = sizeof (addr);
303
304     int l = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP),
305         c = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
306     if (l == -1 || c == -1)
307         goto error;
308
309     memset (&addr, 0, sizeof (addr));
310     addr.sin_family = AF_INET;
311     addr.sin_addr.s_addr = htonl (INADDR_LOOPBACK);
312     if (bind (l, (struct sockaddr *)&addr, sizeof (addr))
313      || getsockname (l, (struct sockaddr *)&addr, &addrlen)
314      || listen (l, 1)
315      || connect (c, (struct sockaddr *)&addr, addrlen))
316         goto error;
317
318     int a = accept (l, NULL, NULL);
319     if (a == -1)
320         goto error;
321
322     close (l);
323     //shutdown (a, 0);
324     //shutdown (c, 1);
325     fd[0] = c;
326     fd[1] = a;
327     return 0;
328
329 error:
330     if (l != -1)
331         close (l);
332     if (c != -1)
333         close (c);
334     return -1;
335 }
336 #endif /* WIN32 || __OS2__ */
337
338 static vlc_mutex_t pipe_lock = VLC_STATIC_MUTEX;
339
340 /**
341  * Returns the readable end of a pipe that becomes readable once termination
342  * of the object is requested (vlc_object_kill()).
343  * This can be used to wake-up out of a select() or poll() event loop, such
344  * typically when doing network I/O.
345  *
346  * Note that the pipe will remain the same for the lifetime of the object.
347  * DO NOT read the pipe nor close it yourself. Ever.
348  *
349  * @param obj object that would be "killed"
350  * @return a readable pipe descriptor, or -1 on error.
351  */
352 int vlc_object_waitpipe( vlc_object_t *obj )
353 {
354     vlc_object_internals_t *internals = vlc_internals( obj );
355
356     vlc_mutex_lock (&pipe_lock);
357     if (internals->pipes[0] == -1)
358     {
359         /* This can only ever happen if someone killed us without locking: */
360         assert (internals->pipes[1] == -1);
361
362         /* pipe() is not a cancellation point, but write() is and eventfd() is
363          * unspecified (not in POSIX). */
364         int canc = vlc_savecancel ();
365 #if defined (HAVE_SYS_EVENTFD_H)
366         internals->pipes[0] = internals->pipes[1] = eventfd (0, EFD_CLOEXEC);
367         if (internals->pipes[0] == -1)
368 #endif
369         {
370             if (vlc_pipe (internals->pipes))
371                 internals->pipes[0] = internals->pipes[1] = -1;
372         }
373
374         if (internals->pipes[0] != -1 && obj->b_die)
375         {   /* Race condition: vlc_object_kill() already invoked! */
376             msg_Dbg (obj, "waitpipe: object already dying");
377             write (internals->pipes[1], &(uint64_t){ 1 }, sizeof (uint64_t));
378         }
379         vlc_restorecancel (canc);
380     }
381     vlc_mutex_unlock (&pipe_lock);
382     return internals->pipes[0];
383 }
384
385 #undef vlc_object_kill
386 /**
387  * Requests termination of an object, cancels the object thread, and make the
388  * object wait pipe (if it exists) readable. Not a cancellation point.
389  */
390 void vlc_object_kill( vlc_object_t *p_this )
391 {
392     vlc_object_internals_t *priv = vlc_internals( p_this );
393     int fd = -1;
394
395     vlc_mutex_lock( &pipe_lock );
396     if( !p_this->b_die )
397     {
398         fd = priv->pipes[1];
399         p_this->b_die = true;
400     }
401
402     /* This also serves as a memory barrier toward vlc_object_alive(): */
403     vlc_mutex_unlock( &pipe_lock );
404
405     if (fd != -1)
406     {
407         int canc = vlc_savecancel ();
408
409         /* write _after_ setting b_die, so vlc_object_alive() returns false */
410         write (fd, &(uint64_t){ 1 }, sizeof (uint64_t));
411         msg_Dbg (p_this, "waitpipe: object killed");
412         vlc_restorecancel (canc);
413     }
414 }
415
416 #undef vlc_object_find_name
417 /**
418  * Finds a named object and increment its reference count.
419  * Beware that objects found in this manner can be "owned" by another thread,
420  * be of _any_ type, and be attached to any module (if any). With such an
421  * object reference, you can set or get object variables, emit log messages,
422  * and read write-once object parameters (psz_object_type, etc).
423  * You CANNOT cast the object to a more specific object type, and you
424  * definitely cannot invoke object type-specific callbacks with this.
425  *
426  * @param p_this object to search from
427  * @param psz_name name of the object to search for
428  *
429  * @return a matching object (must be released by the caller),
430  * or NULL on error.
431  */
432 vlc_object_t *vlc_object_find_name( vlc_object_t *p_this, const char *psz_name )
433 {
434     vlc_object_t *p_found;
435
436     /* Reading psz_object_name from a separate inhibits thread-safety.
437      * Use a libvlc address variable instead for that sort of things! */
438     msg_Err( p_this, "%s(\"%s\") is not safe!", __func__, psz_name );
439
440     libvlc_lock (p_this->p_libvlc);
441     vlc_mutex_lock (&name_lock);
442     p_found = FindName (vlc_internals (p_this), psz_name);
443     vlc_mutex_unlock (&name_lock);
444     libvlc_unlock (p_this->p_libvlc);
445     return p_found;
446 }
447
448 #undef vlc_object_hold
449 /**
450  * Increment an object reference counter.
451  */
452 void * vlc_object_hold( vlc_object_t *p_this )
453 {
454     vlc_object_internals_t *internals = vlc_internals( p_this );
455
456     vlc_spin_lock( &internals->ref_spin );
457     /* Avoid obvious freed object uses */
458     assert( internals->i_refcount > 0 );
459     /* Increment the counter */
460     internals->i_refcount++;
461     vlc_spin_unlock( &internals->ref_spin );
462     return p_this;
463 }
464
465 #undef vlc_object_release
466 /**
467  * Drops a reference to an object (decrements the reference count).
468  * If the count reaches zero, the object is destroyed.
469  */
470 void vlc_object_release( vlc_object_t *p_this )
471 {
472     vlc_object_internals_t *internals = vlc_internals( p_this );
473     vlc_object_t *parent = NULL;
474     bool b_should_destroy;
475
476     vlc_spin_lock( &internals->ref_spin );
477     assert( internals->i_refcount > 0 );
478
479     if( internals->i_refcount > 1 )
480     {
481         /* Fast path */
482         /* There are still other references to the object */
483         internals->i_refcount--;
484         vlc_spin_unlock( &internals->ref_spin );
485         return;
486     }
487     vlc_spin_unlock( &internals->ref_spin );
488
489     /* Slow path */
490     /* Remember that we cannot hold the spin while waiting on the mutex */
491     libvlc_lock (p_this->p_libvlc);
492     /* Take the spin again. Note that another thread may have held the
493      * object in the (very short) mean time. */
494     vlc_spin_lock( &internals->ref_spin );
495     b_should_destroy = --internals->i_refcount == 0;
496     vlc_spin_unlock( &internals->ref_spin );
497
498     if( b_should_destroy )
499     {
500         /* Detach from parent to protect against vlc_object_find_name() */
501         parent = p_this->p_parent;
502         if (likely(parent))
503         {
504            /* Unlink */
505            if (internals->prev != NULL)
506                internals->prev->next = internals->next;
507            else
508                vlc_internals(parent)->first = internals->next;
509            if (internals->next != NULL)
510                internals->next->prev = internals->prev;
511         }
512
513         /* We have no children */
514         assert (internals->first == NULL);
515     }
516     libvlc_unlock (p_this->p_libvlc);
517
518     if( b_should_destroy )
519     {
520         int canc;
521
522         canc = vlc_savecancel ();
523         vlc_object_destroy( p_this );
524         vlc_restorecancel (canc);
525         if (parent)
526             vlc_object_release (parent);
527     }
528 }
529
530 #undef vlc_list_children
531 /**
532  * Gets the list of children of an objects, and increment their reference
533  * count.
534  * @return a list (possibly empty) or NULL in case of error.
535  */
536 vlc_list_t *vlc_list_children( vlc_object_t *obj )
537 {
538     vlc_list_t *l;
539     vlc_object_internals_t *priv;
540     unsigned count = 0;
541
542     libvlc_lock (obj->p_libvlc);
543     for (priv = vlc_internals (obj)->first; priv; priv = priv->next)
544          count++;
545     l = NewList (count);
546     if (likely(l != NULL))
547     {
548         unsigned i = 0;
549
550         for (priv = vlc_internals (obj)->first; priv; priv = priv->next)
551             l->p_values[i++].p_object = vlc_object_hold (vlc_externals (priv));
552     }
553     libvlc_unlock (obj->p_libvlc);
554     return l;
555 }
556
557 static void DumpVariable (const void *data, const VISIT which, const int depth)
558 {
559     if (which != postorder && which != leaf)
560         return;
561     (void) depth;
562
563     const variable_t *p_var = *(const variable_t **)data;
564     const char *psz_type = "unknown";
565
566     switch( p_var->i_type & VLC_VAR_TYPE )
567     {
568 #define MYCASE( type, nice )    \
569         case VLC_VAR_ ## type:  \
570             psz_type = nice;    \
571             break;
572         MYCASE( VOID, "void" );
573         MYCASE( BOOL, "bool" );
574         MYCASE( INTEGER, "integer" );
575         MYCASE( HOTKEY, "hotkey" );
576         MYCASE( STRING, "string" );
577         MYCASE( VARIABLE, "variable" );
578         MYCASE( FLOAT, "float" );
579         MYCASE( TIME, "time" );
580         MYCASE( COORDS, "coords" );
581         MYCASE( ADDRESS, "address" );
582 #undef MYCASE
583     }
584     printf( " *-o \"%s\" (%s", p_var->psz_name, psz_type );
585     if( p_var->psz_text )
586         printf( ", %s", p_var->psz_text );
587     fputc( ')', stdout );
588     if( p_var->i_type & VLC_VAR_HASCHOICE )
589         fputs( ", has choices", stdout );
590     if( p_var->i_type & VLC_VAR_ISCOMMAND )
591         fputs( ", command", stdout );
592     if( p_var->i_entries )
593         printf( ", %d callbacks", p_var->i_entries );
594     switch( p_var->i_type & VLC_VAR_CLASS )
595     {
596         case VLC_VAR_VOID:
597             break;
598         case VLC_VAR_BOOL:
599             printf( ": %s", p_var->val.b_bool ? "true" : "false" );
600             break;
601         case VLC_VAR_INTEGER:
602             printf( ": %"PRId64, p_var->val.i_int );
603             break;
604         case VLC_VAR_STRING:
605             printf( ": \"%s\"", p_var->val.psz_string );
606             break;
607         case VLC_VAR_FLOAT:
608             printf( ": %f", p_var->val.f_float );
609             break;
610         case VLC_VAR_TIME:
611             printf( ": %"PRIi64, (int64_t)p_var->val.i_time );
612             break;
613         case VLC_VAR_COORDS:
614             printf( ": %"PRId32"x%"PRId32,
615                     p_var->val.coords.x, p_var->val.coords.y );
616             break;
617         case VLC_VAR_ADDRESS:
618             printf( ": %p", p_var->val.p_address );
619             break;
620     }
621     fputc( '\n', stdout );
622 }
623
624 /*****************************************************************************
625  * DumpCommand: print the current vlc structure
626  *****************************************************************************
627  * This function prints either an ASCII tree showing the connections between
628  * vlc objects, and additional information such as their refcount, thread ID,
629  * etc. (command "tree"), or the same data as a simple list (command "list").
630  *****************************************************************************/
631 static int DumpCommand( vlc_object_t *p_this, char const *psz_cmd,
632                         vlc_value_t oldval, vlc_value_t newval, void *p_data )
633 {
634     (void)oldval;
635     vlc_object_t *p_object = NULL;
636
637     if( *newval.psz_string )
638     {
639         /* try using the object's name to find it */
640         p_object = vlc_object_find_name( p_data, newval.psz_string );
641         if( !p_object )
642             return VLC_ENOOBJ;
643     }
644
645     libvlc_lock (p_this->p_libvlc);
646     if( *psz_cmd == 't' )
647     {
648         char psz_foo[2 * MAX_DUMPSTRUCTURE_DEPTH + 1];
649
650         if( !p_object )
651             p_object = VLC_OBJECT(p_this->p_libvlc);
652
653         psz_foo[0] = '|';
654         DumpStructure( vlc_internals(p_object), 0, psz_foo );
655     }
656     else if( *psz_cmd == 'v' )
657     {
658         if( !p_object )
659             p_object = p_this->p_libvlc ? VLC_OBJECT(p_this->p_libvlc) : p_this;
660
661         PrintObject( vlc_internals(p_object), "" );
662         vlc_mutex_lock( &vlc_internals( p_object )->var_lock );
663         if( vlc_internals( p_object )->var_root == NULL )
664             puts( " `-o No variables" );
665         else
666             twalk( vlc_internals( p_object )->var_root, DumpVariable );
667         vlc_mutex_unlock( &vlc_internals( p_object )->var_lock );
668     }
669     libvlc_unlock (p_this->p_libvlc);
670
671     if( *newval.psz_string )
672     {
673         vlc_object_release( p_object );
674     }
675     return VLC_SUCCESS;
676 }
677
678 /*****************************************************************************
679  * vlc_list_release: free a list previously allocated by vlc_list_find
680  *****************************************************************************
681  * This function decreases the refcount of all objects in the list and
682  * frees the list.
683  *****************************************************************************/
684 void vlc_list_release( vlc_list_t *p_list )
685 {
686     int i_index;
687
688     for( i_index = 0; i_index < p_list->i_count; i_index++ )
689     {
690         vlc_object_release( p_list->p_values[i_index].p_object );
691     }
692
693     free( p_list->p_values );
694     free( p_list );
695 }
696
697 /* Following functions are local */
698
699 static vlc_object_t *FindName (vlc_object_internals_t *priv, const char *name)
700 {
701     if (priv->psz_name != NULL && !strcmp (priv->psz_name, name))
702         return vlc_object_hold (vlc_externals (priv));
703
704     for (priv = priv->first; priv != NULL; priv = priv->next)
705     {
706         vlc_object_t *found = FindName (priv, name);
707         if (found != NULL)
708             return found;
709     }
710     return NULL;
711 }
712
713 static void PrintObject( vlc_object_internals_t *priv,
714                          const char *psz_prefix )
715 {
716     char psz_refcount[20], psz_name[50], psz_parent[20];
717
718     int canc = vlc_savecancel ();
719     memset( &psz_name, 0, sizeof(psz_name) );
720
721     vlc_mutex_lock (&name_lock);
722     if (priv->psz_name != NULL)
723     {
724         snprintf( psz_name, 49, " \"%s\"", priv->psz_name );
725         if( psz_name[48] )
726             psz_name[48] = '\"';
727     }
728     vlc_mutex_unlock (&name_lock);
729
730     psz_refcount[0] = '\0';
731     if( priv->i_refcount > 0 )
732         snprintf( psz_refcount, 19, ", %u refs", priv->i_refcount );
733
734     psz_parent[0] = '\0';
735     /* FIXME: need structure lock!!! */
736     if( vlc_externals(priv)->p_parent )
737         snprintf( psz_parent, 19, ", parent %p",
738                   vlc_externals(priv)->p_parent );
739
740     printf( " %so %p %s%s%s%s\n", psz_prefix,
741             vlc_externals(priv), vlc_externals(priv)->psz_object_type,
742             psz_name, psz_refcount, psz_parent );
743     vlc_restorecancel (canc);
744 }
745
746 static void DumpStructure (vlc_object_internals_t *priv, unsigned i_level,
747                            char *psz_foo)
748 {
749     char i_back = psz_foo[i_level];
750     psz_foo[i_level] = '\0';
751
752     PrintObject (priv, psz_foo);
753
754     psz_foo[i_level] = i_back;
755
756     if( i_level / 2 >= MAX_DUMPSTRUCTURE_DEPTH )
757     {
758         msg_Warn( vlc_externals(priv), "structure tree is too deep" );
759         return;
760     }
761
762     for (priv = priv->first; priv != NULL; priv = priv->next)
763     {
764         if( i_level )
765         {
766             psz_foo[i_level-1] = ' ';
767
768             if( psz_foo[i_level-2] == '`' )
769             {
770                 psz_foo[i_level-2] = ' ';
771             }
772         }
773
774         psz_foo[i_level] = priv->next ? '|' : '`';
775         psz_foo[i_level+1] = '-';
776         psz_foo[i_level+2] = '\0';
777
778         DumpStructure (priv, i_level + 2, psz_foo);
779     }
780 }
781
782 static vlc_list_t * NewList( int i_count )
783 {
784     vlc_list_t * p_list = malloc( sizeof( vlc_list_t ) );
785     if( p_list == NULL )
786         return NULL;
787
788     p_list->i_count = i_count;
789
790     if( i_count == 0 )
791     {
792         p_list->p_values = NULL;
793         return p_list;
794     }
795
796     p_list->p_values = malloc( i_count * sizeof( vlc_value_t ) );
797     if( p_list->p_values == NULL )
798     {
799         p_list->i_count = 0;
800         return p_list;
801     }
802
803     return p_list;
804 }