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
7 * Authors: Samuel Hocevar <sam@zoy.org>
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.
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.
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 *****************************************************************************/
26 * This file contains the functions to handle the vlc_object_t type
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.
33 /*****************************************************************************
35 *****************************************************************************/
40 #include <vlc_common.h>
42 #include "../libvlc.h"
44 #include "audio_output/aout_internal.h"
46 #include "vlc_interface.h"
47 #include "vlc_codec.h"
49 #include "variables.h"
56 # include <sys/socket.h>
57 # include <netinet/in.h>
58 # include <unistd.h> // close(), write()
61 # include <winsock2.h>
62 # include <ws2tcpip.h>
64 # define read( a, b, c ) recv (a, b, c, 0)
66 # define write( a, b, c ) send (a, b, c, 0)
68 # define close( a ) closesocket (a)
77 #if defined (HAVE_SYS_EVENTFD_H)
78 # include <sys/eventfd.h>
80 # define EFD_CLOEXEC 0
81 # warning EFD_CLOEXEC missing. Consider updating libc.
86 /*****************************************************************************
88 *****************************************************************************/
89 static int DumpCommand( vlc_object_t
*, char const *,
90 vlc_value_t
, vlc_value_t
, void * );
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 * );
96 static vlc_list_t
* NewList ( int );
98 static void vlc_object_destroy( vlc_object_t
*p_this
);
100 /*****************************************************************************
101 * Local structure lock
102 *****************************************************************************/
103 static void libvlc_lock (libvlc_int_t
*p_libvlc
)
105 vlc_mutex_lock (&(libvlc_priv (p_libvlc
)->structure_lock
));
108 static void libvlc_unlock (libvlc_int_t
*p_libvlc
)
110 vlc_mutex_unlock (&(libvlc_priv (p_libvlc
)->structure_lock
));
113 #undef vlc_custom_create
114 void *vlc_custom_create (vlc_object_t
*parent
, size_t length
,
115 const char *typename
)
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).
123 * This function initializes the LibVLC and common data,
124 * and zeroes the rest.
126 assert (length
>= sizeof (vlc_object_t
));
128 vlc_object_internals_t
*priv
= malloc (sizeof (*priv
) + length
);
129 if (unlikely(priv
== 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 atomic_init (&priv
->alive
, true);
137 atomic_init (&priv
->refs
, 1);
138 priv
->pf_destructor
= NULL
;
142 vlc_object_t
*obj
= (vlc_object_t
*)(priv
+ 1);
143 obj
->psz_object_type
= typename
;
144 obj
->psz_header
= NULL
;
145 obj
->b_force
= false;
146 memset (obj
+ 1, 0, length
- sizeof (*obj
)); /* type-specific stuff */
148 if (likely(parent
!= NULL
))
150 vlc_object_internals_t
*papriv
= vlc_internals (parent
);
152 obj
->i_flags
= parent
->i_flags
;
153 obj
->p_libvlc
= parent
->p_libvlc
;
155 /* Attach the child to its parent (no lock needed) */
156 obj
->p_parent
= vlc_object_hold (parent
);
158 /* Attach the parent to its child (structure lock needed) */
159 libvlc_lock (obj
->p_libvlc
);
160 priv
->next
= papriv
->first
;
161 if (priv
->next
!= NULL
)
162 priv
->next
->prev
= priv
;
163 papriv
->first
= priv
;
164 libvlc_unlock (obj
->p_libvlc
);
168 libvlc_int_t
*self
= (libvlc_int_t
*)obj
;
171 obj
->p_libvlc
= self
;
172 obj
->p_parent
= NULL
;
174 vlc_mutex_init (&(libvlc_priv (self
)->structure_lock
));
176 /* TODO: should be in src/libvlc.c */
177 int canc
= vlc_savecancel ();
178 var_Create (obj
, "tree", VLC_VAR_STRING
| VLC_VAR_ISCOMMAND
);
179 var_AddCallback (obj
, "tree", DumpCommand
, obj
);
180 var_Create (obj
, "vars", VLC_VAR_STRING
| VLC_VAR_ISCOMMAND
);
181 var_AddCallback (obj
, "vars", DumpCommand
, obj
);
182 vlc_restorecancel (canc
);
188 #undef vlc_object_create
190 * Allocates and initializes a vlc object.
192 * @param i_size object byte size
194 * @return the new object, or NULL on error.
196 void *vlc_object_create( vlc_object_t
*p_this
, size_t i_size
)
198 return vlc_custom_create( p_this
, i_size
, "generic" );
201 #undef vlc_object_set_destructor
203 ****************************************************************************
204 * Set the destructor of a vlc object
206 * This function sets the destructor of the vlc object. It will be called
207 * when the object is destroyed when the its refcount reaches 0.
208 * (It is called by the internal function vlc_object_destroy())
209 *****************************************************************************/
210 void vlc_object_set_destructor( vlc_object_t
*p_this
,
211 vlc_destructor_t pf_destructor
)
213 vlc_object_internals_t
*p_priv
= vlc_internals(p_this
);
215 p_priv
->pf_destructor
= pf_destructor
;
218 static vlc_mutex_t name_lock
= VLC_STATIC_MUTEX
;
220 #undef vlc_object_set_name
221 int vlc_object_set_name(vlc_object_t
*obj
, const char *name
)
223 vlc_object_internals_t
*priv
= vlc_internals(obj
);
224 char *newname
= name
? strdup (name
) : NULL
;
227 vlc_mutex_lock (&name_lock
);
228 oldname
= priv
->psz_name
;
229 priv
->psz_name
= newname
;
230 vlc_mutex_unlock (&name_lock
);
233 return (priv
->psz_name
|| !name
) ? VLC_SUCCESS
: VLC_ENOMEM
;
236 #undef vlc_object_get_name
237 char *vlc_object_get_name(const vlc_object_t
*obj
)
239 vlc_object_internals_t
*priv
= vlc_internals(obj
);
242 vlc_mutex_lock (&name_lock
);
243 name
= priv
->psz_name
? strdup (priv
->psz_name
) : NULL
;
244 vlc_mutex_unlock (&name_lock
);
250 * Destroys a VLC object once it has no more references.
252 * This function must be called with cancellation disabled (currently).
254 static void vlc_object_destroy( vlc_object_t
*p_this
)
256 vlc_object_internals_t
*p_priv
= vlc_internals( p_this
);
258 /* Call the custom "subclass" destructor */
259 if( p_priv
->pf_destructor
)
260 p_priv
->pf_destructor( p_this
);
262 if (unlikely(p_this
== VLC_OBJECT(p_this
->p_libvlc
)))
264 /* TODO: should be in src/libvlc.c */
265 var_DelCallback (p_this
, "tree", DumpCommand
, p_this
);
266 var_DelCallback (p_this
, "vars", DumpCommand
, p_this
);
269 /* Destroy the associated variables. */
270 var_DestroyAll( p_this
);
272 vlc_cond_destroy( &p_priv
->var_wait
);
273 vlc_mutex_destroy( &p_priv
->var_lock
);
275 free( p_this
->psz_header
);
277 free( p_priv
->psz_name
);
279 if( p_priv
->pipes
[1] != -1 && p_priv
->pipes
[1] != p_priv
->pipes
[0] )
280 close( p_priv
->pipes
[1] );
281 if( p_priv
->pipes
[0] != -1 )
282 close( p_priv
->pipes
[0] );
283 if( VLC_OBJECT(p_this
->p_libvlc
) == p_this
)
284 vlc_mutex_destroy (&(libvlc_priv ((libvlc_int_t
*)p_this
)->structure_lock
));
290 #if defined(_WIN32) || defined(__OS2__)
292 * select()-able pipes emulated using Winsock
294 # define vlc_pipe selectable_pipe
295 static int selectable_pipe (int fd
[2])
297 struct sockaddr_in addr
;
298 int addrlen
= sizeof (addr
);
300 int l
= socket (PF_INET
, SOCK_STREAM
, IPPROTO_TCP
),
301 c
= socket (PF_INET
, SOCK_STREAM
, IPPROTO_TCP
);
302 if (l
== -1 || c
== -1)
305 memset (&addr
, 0, sizeof (addr
));
306 addr
.sin_family
= AF_INET
;
307 addr
.sin_addr
.s_addr
= htonl (INADDR_LOOPBACK
);
308 if (bind (l
, (struct sockaddr
*)&addr
, sizeof (addr
))
309 || getsockname (l
, (struct sockaddr
*)&addr
, &addrlen
)
311 || connect (c
, (struct sockaddr
*)&addr
, addrlen
))
314 int a
= accept (l
, NULL
, NULL
);
332 #endif /* _WIN32 || __OS2__ */
334 static vlc_mutex_t pipe_lock
= VLC_STATIC_MUTEX
;
337 * Returns the readable end of a pipe that becomes readable once termination
338 * of the object is requested (vlc_object_kill()).
339 * This can be used to wake-up out of a select() or poll() event loop, such
340 * typically when doing network I/O.
342 * Note that the pipe will remain the same for the lifetime of the object.
343 * DO NOT read the pipe nor close it yourself. Ever.
345 * @param obj object that would be "killed"
346 * @return a readable pipe descriptor, or -1 on error.
348 int vlc_object_waitpipe( vlc_object_t
*obj
)
350 vlc_object_internals_t
*internals
= vlc_internals( obj
);
352 vlc_mutex_lock (&pipe_lock
);
353 if (internals
->pipes
[0] == -1)
355 /* This can only ever happen if someone killed us without locking: */
356 assert (internals
->pipes
[1] == -1);
358 /* pipe() is not a cancellation point, but write() is and eventfd() is
359 * unspecified (not in POSIX). */
360 int canc
= vlc_savecancel ();
361 #if defined (HAVE_SYS_EVENTFD_H)
362 internals
->pipes
[0] = internals
->pipes
[1] = eventfd (0, EFD_CLOEXEC
);
363 if (internals
->pipes
[0] == -1)
366 if (vlc_pipe (internals
->pipes
))
367 internals
->pipes
[0] = internals
->pipes
[1] = -1;
370 if (internals
->pipes
[0] != -1 && !atomic_load (&internals
->alive
))
371 { /* Race condition: vlc_object_kill() already invoked! */
372 msg_Dbg (obj
, "waitpipe: object already dying");
373 write (internals
->pipes
[1], &(uint64_t){ 1 }, sizeof (uint64_t));
375 vlc_restorecancel (canc
);
377 vlc_mutex_unlock (&pipe_lock
);
378 return internals
->pipes
[0];
382 * Hack for input objects. Should be removed eventually.
384 void ObjectKillChildrens( vlc_object_t
*p_obj
)
386 /* FIXME ObjectKillChildrens seems a very bad idea in fact */
387 /*if( p_obj == VLC_OBJECT(p_input->p->p_sout) ) return;*/
389 vlc_object_internals_t
*priv
= vlc_internals (p_obj
);
390 if (atomic_exchange (&priv
->alive
, false))
394 vlc_mutex_lock (&pipe_lock
);
396 vlc_mutex_unlock (&pipe_lock
);
399 write (fd
, &(uint64_t){ 1 }, sizeof (uint64_t));
400 msg_Dbg (p_obj
, "object waitpipe triggered");
404 vlc_list_t
*p_list
= vlc_list_children( p_obj
);
405 for( int i
= 0; i
< p_list
->i_count
; i
++ )
406 ObjectKillChildrens( p_list
->p_values
[i
].p_object
);
407 vlc_list_release( p_list
);
411 #undef vlc_object_find_name
413 * Finds a named object and increment its reference count.
414 * Beware that objects found in this manner can be "owned" by another thread,
415 * be of _any_ type, and be attached to any module (if any). With such an
416 * object reference, you can set or get object variables, emit log messages,
417 * and read write-once object parameters (psz_object_type, etc).
418 * You CANNOT cast the object to a more specific object type, and you
419 * definitely cannot invoke object type-specific callbacks with this.
421 * @param p_this object to search from
422 * @param psz_name name of the object to search for
424 * @return a matching object (must be released by the caller),
427 vlc_object_t
*vlc_object_find_name( vlc_object_t
*p_this
, const char *psz_name
)
429 vlc_object_t
*p_found
;
431 /* The object name is not thread-safe, provides no warranty that the
432 * object is fully initialized and still active, and that its owner can
433 * deal with asynchronous and external state changes. There may be multiple
434 * objects with the same name, and the function may fail even if a matching
435 * object exists. DO NOT USE THIS IN NEW CODE. */
437 /* This was officially deprecated on August 19 2009. For the convenience of
438 * wannabe code janitors, this is the list of names that remain used
439 * and unfixed since then. */
440 static const char bad
[][11] = { "adjust", "clone", "colorthres",
441 "erase", "extract", "gradient", "logo", "marq", "motionblur", "puzzle",
442 "rotate", "sharpen", "transform", "v4l2", "wall" };
443 static const char poor
[][13] = { "invert", "magnify", "motiondetect",
444 "psychedelic", "ripple", "wave" };
445 if( bsearch( psz_name
, bad
, 15, 11, (void *)strcmp
) == NULL
446 && bsearch( psz_name
, poor
, 6, 13, (void *)strcmp
) == NULL
)
448 msg_Err( p_this
, "looking for object \"%s\"... FIXME XXX", psz_name
);
451 libvlc_lock (p_this
->p_libvlc
);
452 vlc_mutex_lock (&name_lock
);
453 p_found
= FindName (vlc_internals (p_this
), psz_name
);
454 vlc_mutex_unlock (&name_lock
);
455 libvlc_unlock (p_this
->p_libvlc
);
459 #undef vlc_object_hold
461 * Increment an object reference counter.
463 void * vlc_object_hold( vlc_object_t
*p_this
)
465 vlc_object_internals_t
*internals
= vlc_internals( p_this
);
467 unsigned refs
= atomic_fetch_add (&internals
->refs
, 1);
468 assert (refs
> 0); /* Avoid obvious freed object uses */
470 atomic_fetch_add (&internals
->refs
, 1);
475 #undef vlc_object_release
477 * Drops a reference to an object (decrements the reference count).
478 * If the count reaches zero, the object is destroyed.
480 void vlc_object_release( vlc_object_t
*p_this
)
482 vlc_object_internals_t
*internals
= vlc_internals( p_this
);
483 vlc_object_t
*parent
= NULL
;
484 unsigned refs
= atomic_load (&internals
->refs
);
489 if (atomic_compare_exchange_weak (&internals
->refs
, &refs
, refs
- 1))
490 return; /* There are still other references to the object */
496 libvlc_lock (p_this
->p_libvlc
);
497 refs
= atomic_fetch_sub (&internals
->refs
, 1);
500 if (likely(refs
== 1))
502 /* Detach from parent to protect against vlc_object_find_name() */
503 parent
= p_this
->p_parent
;
507 vlc_object_internals_t
*prev
= internals
->prev
;
508 vlc_object_internals_t
*next
= internals
->next
;
513 vlc_internals (parent
)->first
= next
;
518 /* We have no children */
519 assert (internals
->first
== NULL
);
521 libvlc_unlock (p_this
->p_libvlc
);
523 if (likely(refs
== 1))
525 int canc
= vlc_savecancel ();
526 vlc_object_destroy( p_this
);
527 vlc_restorecancel (canc
);
529 vlc_object_release (parent
);
533 #undef vlc_object_alive
535 * This function returns true, except when it returns false.
536 * \warning Do not use this function. Ever. You were warned.
538 bool vlc_object_alive(vlc_object_t
*obj
)
540 vlc_object_internals_t
*internals
= vlc_internals (obj
);
541 return atomic_load (&internals
->alive
);
544 #undef vlc_list_children
546 * Gets the list of children of an object, and increment their reference
548 * @return a list (possibly empty) or NULL in case of error.
550 vlc_list_t
*vlc_list_children( vlc_object_t
*obj
)
553 vlc_object_internals_t
*priv
;
556 libvlc_lock (obj
->p_libvlc
);
557 for (priv
= vlc_internals (obj
)->first
; priv
; priv
= priv
->next
)
560 if (likely(l
!= NULL
))
564 for (priv
= vlc_internals (obj
)->first
; priv
; priv
= priv
->next
)
565 l
->p_values
[i
++].p_object
= vlc_object_hold (vlc_externals (priv
));
567 libvlc_unlock (obj
->p_libvlc
);
571 static void DumpVariable (const void *data
, const VISIT which
, const int depth
)
573 if (which
!= postorder
&& which
!= leaf
)
577 const variable_t
*p_var
= *(const variable_t
**)data
;
578 const char *psz_type
= "unknown";
580 switch( p_var
->i_type
& VLC_VAR_TYPE
)
582 #define MYCASE( type, nice ) \
583 case VLC_VAR_ ## type: \
586 MYCASE( VOID
, "void" );
587 MYCASE( BOOL
, "bool" );
588 MYCASE( INTEGER
, "integer" );
589 MYCASE( HOTKEY
, "hotkey" );
590 MYCASE( STRING
, "string" );
591 MYCASE( VARIABLE
, "variable" );
592 MYCASE( FLOAT
, "float" );
593 MYCASE( TIME
, "time" );
594 MYCASE( COORDS
, "coords" );
595 MYCASE( ADDRESS
, "address" );
598 printf( " *-o \"%s\" (%s", p_var
->psz_name
, psz_type
);
599 if( p_var
->psz_text
)
600 printf( ", %s", p_var
->psz_text
);
601 fputc( ')', stdout
);
602 if( p_var
->i_type
& VLC_VAR_HASCHOICE
)
603 fputs( ", has choices", stdout
);
604 if( p_var
->i_type
& VLC_VAR_ISCOMMAND
)
605 fputs( ", command", stdout
);
606 if( p_var
->i_entries
)
607 printf( ", %d callbacks", p_var
->i_entries
);
608 switch( p_var
->i_type
& VLC_VAR_CLASS
)
613 printf( ": %s", p_var
->val
.b_bool
? "true" : "false" );
615 case VLC_VAR_INTEGER
:
616 printf( ": %"PRId64
, p_var
->val
.i_int
);
619 printf( ": \"%s\"", p_var
->val
.psz_string
);
622 printf( ": %f", p_var
->val
.f_float
);
625 printf( ": %"PRIi64
, (int64_t)p_var
->val
.i_time
);
628 printf( ": %"PRId32
"x%"PRId32
,
629 p_var
->val
.coords
.x
, p_var
->val
.coords
.y
);
631 case VLC_VAR_ADDRESS
:
632 printf( ": %p", p_var
->val
.p_address
);
635 fputc( '\n', stdout
);
638 /*****************************************************************************
639 * DumpCommand: print the current vlc structure
640 *****************************************************************************
641 * This function prints either an ASCII tree showing the connections between
642 * vlc objects, and additional information such as their refcount, thread ID,
643 * etc. (command "tree"), or the same data as a simple list (command "list").
644 *****************************************************************************/
645 static int DumpCommand( vlc_object_t
*p_this
, char const *psz_cmd
,
646 vlc_value_t oldval
, vlc_value_t newval
, void *p_data
)
649 vlc_object_t
*p_object
= NULL
;
651 if( *newval
.psz_string
)
653 /* try using the object's name to find it */
654 p_object
= vlc_object_find_name( p_data
, newval
.psz_string
);
659 libvlc_lock (p_this
->p_libvlc
);
660 if( *psz_cmd
== 't' )
662 char psz_foo
[2 * MAX_DUMPSTRUCTURE_DEPTH
+ 1];
665 p_object
= VLC_OBJECT(p_this
->p_libvlc
);
668 DumpStructure( vlc_internals(p_object
), 0, psz_foo
);
670 else if( *psz_cmd
== 'v' )
673 p_object
= p_this
->p_libvlc
? VLC_OBJECT(p_this
->p_libvlc
) : p_this
;
675 PrintObject( vlc_internals(p_object
), "" );
676 vlc_mutex_lock( &vlc_internals( p_object
)->var_lock
);
677 if( vlc_internals( p_object
)->var_root
== NULL
)
678 puts( " `-o No variables" );
680 twalk( vlc_internals( p_object
)->var_root
, DumpVariable
);
681 vlc_mutex_unlock( &vlc_internals( p_object
)->var_lock
);
683 libvlc_unlock (p_this
->p_libvlc
);
685 if( *newval
.psz_string
)
687 vlc_object_release( p_object
);
692 /*****************************************************************************
693 * vlc_list_release: free a list previously allocated by vlc_list_find
694 *****************************************************************************
695 * This function decreases the refcount of all objects in the list and
697 *****************************************************************************/
698 void vlc_list_release( vlc_list_t
*p_list
)
702 for( i_index
= 0; i_index
< p_list
->i_count
; i_index
++ )
704 vlc_object_release( p_list
->p_values
[i_index
].p_object
);
707 free( p_list
->p_values
);
711 /* Following functions are local */
713 static vlc_object_t
*FindName (vlc_object_internals_t
*priv
, const char *name
)
715 if (priv
->psz_name
!= NULL
&& !strcmp (priv
->psz_name
, name
))
716 return vlc_object_hold (vlc_externals (priv
));
718 for (priv
= priv
->first
; priv
!= NULL
; priv
= priv
->next
)
720 vlc_object_t
*found
= FindName (priv
, name
);
727 static void PrintObject( vlc_object_internals_t
*priv
,
728 const char *psz_prefix
)
730 char psz_refcount
[20], psz_name
[50], psz_parent
[20];
732 int canc
= vlc_savecancel ();
733 memset( &psz_name
, 0, sizeof(psz_name
) );
735 vlc_mutex_lock (&name_lock
);
736 if (priv
->psz_name
!= NULL
)
738 snprintf( psz_name
, 49, " \"%s\"", priv
->psz_name
);
742 vlc_mutex_unlock (&name_lock
);
744 snprintf( psz_refcount
, 19, ", %u refs", atomic_load( &priv
->refs
) );
746 psz_parent
[0] = '\0';
747 /* FIXME: need structure lock!!! */
748 if( vlc_externals(priv
)->p_parent
)
749 snprintf( psz_parent
, 19, ", parent %p",
750 vlc_externals(priv
)->p_parent
);
752 printf( " %so %p %s%s%s%s\n", psz_prefix
,
753 vlc_externals(priv
), vlc_externals(priv
)->psz_object_type
,
754 psz_name
, psz_refcount
, psz_parent
);
755 vlc_restorecancel (canc
);
758 static void DumpStructure (vlc_object_internals_t
*priv
, unsigned i_level
,
761 char i_back
= psz_foo
[i_level
];
762 psz_foo
[i_level
] = '\0';
764 PrintObject (priv
, psz_foo
);
766 psz_foo
[i_level
] = i_back
;
768 if( i_level
/ 2 >= MAX_DUMPSTRUCTURE_DEPTH
)
770 msg_Warn( vlc_externals(priv
), "structure tree is too deep" );
774 for (priv
= priv
->first
; priv
!= NULL
; priv
= priv
->next
)
778 psz_foo
[i_level
-1] = ' ';
780 if( psz_foo
[i_level
-2] == '`' )
782 psz_foo
[i_level
-2] = ' ';
786 psz_foo
[i_level
] = priv
->next
? '|' : '`';
787 psz_foo
[i_level
+1] = '-';
788 psz_foo
[i_level
+2] = '\0';
790 DumpStructure (priv
, i_level
+ 2, psz_foo
);
794 static vlc_list_t
* NewList( int i_count
)
796 vlc_list_t
* p_list
= malloc( sizeof( vlc_list_t
) );
800 p_list
->i_count
= i_count
;
804 p_list
->p_values
= NULL
;
808 p_list
->p_values
= malloc( i_count
* sizeof( vlc_value_t
) );
809 if( p_list
->p_values
== NULL
)