+/* General comparison functions */
+/**
+ * Compare two items using their title or name
+ * @param first: the first item
+ * @param second: the second item
+ * @return -1, 0 or 1 like strcmp
+ */
+static inline int meta_strcasecmp_title( const playlist_item_t *first,
+ const playlist_item_t *second )
+{
+ int i_ret;
+ char *psz_first = input_item_GetTitleFbName( first->p_input );
+ char *psz_second = input_item_GetTitleFbName( second->p_input );
+
+ if( psz_first && psz_second )
+ i_ret = strcasecmp( psz_first, psz_second );
+ else if( !psz_first && psz_second )
+ i_ret = 1;
+ else if( psz_first && !psz_second )
+ i_ret = -1;
+ else
+ i_ret = 0;
+ free( psz_first );
+ free( psz_second );
+
+ return i_ret;
+}
+
+/**
+ * Compare two intems accoring to the given meta type
+ * @param first: the first item
+ * @param second: the second item
+ * @param meta: the meta type to use to sort the items
+ * @param b_integer: true if the meta are integers
+ * @return -1, 0 or 1 like strcmp
+ */
+static inline int meta_sort( const playlist_item_t *first,
+ const playlist_item_t *second,
+ vlc_meta_type_t meta, bool b_integer )
+{
+ int i_ret;
+ char *psz_first = input_item_GetMeta( first->p_input, meta );
+ char *psz_second = input_item_GetMeta( second->p_input, meta );
+
+ /* Nodes go first */
+ if( first->i_children == -1 && second->i_children >= 0 )
+ i_ret = 1;
+ else if( first->i_children >= 0 && second->i_children == -1 )
+ i_ret = -1;
+ /* Both are nodes, sort by name */
+ else if( first->i_children >= 0 && second->i_children >= 0 )
+ i_ret = meta_strcasecmp_title( first, second );
+ /* Both are items */
+ else if( !psz_first && psz_second )
+ i_ret = 1;
+ else if( psz_first && !psz_second )
+ i_ret = -1;
+ /* No meta, sort by name */
+ else if( !psz_first && !psz_second )
+ i_ret = meta_strcasecmp_title( first, second );
+ else
+ {
+ if( b_integer )
+ i_ret = atoi( psz_first ) - atoi( psz_second );
+ else
+ i_ret = strcasecmp( psz_first, psz_second );
+ }
+
+ free( psz_first );
+ free( psz_second );
+ return i_ret;
+}
+
+/* Comparison functions */
+
+/**
+ * Return the comparison function appropriate for the SORT_* and ORDER_*
+ * arguments given, or NULL for SORT_RANDOM.
+ * @param i_mode: a SORT_* enum indicating the field to sort on
+ * @param i_type: ORDER_NORMAL or ORDER_REVERSE
+ * @return function pointer, or NULL for SORT_RANDOM or invalid input
+ */
+typedef int (*sortfn_t)(const void *,const void *);
+static const sortfn_t sorting_fns[NUM_SORT_FNS][2];
+static inline sortfn_t find_sorting_fn( unsigned i_mode, unsigned i_type )
+{
+ if( i_mode>=NUM_SORT_FNS || i_type>1 )
+ return 0;
+ return sorting_fns[i_mode][i_type];
+}
+
+/**
+ * Sort an array of items recursively
+ * @param i_items: number of items
+ * @param pp_items: the array of items
+ * @param p_sortfn: the sorting function
+ * @return nothing
+ */
+static inline
+void playlist_ItemArraySort( unsigned i_items, playlist_item_t **pp_items,
+ sortfn_t p_sortfn )
+{
+ if( p_sortfn )
+ {
+ qsort( pp_items, i_items, sizeof( pp_items[0] ), p_sortfn );
+ }
+ else /* Randomise */
+ {
+ unsigned i_position;
+ unsigned i_new;
+ playlist_item_t *p_temp;
+
+ for( i_position = i_items - 1; i_position > 0; i_position-- )
+ {
+ i_new = ((unsigned)vlc_mrand48()) % (i_position+1);
+ p_temp = pp_items[i_position];
+ pp_items[i_position] = pp_items[i_new];
+ pp_items[i_new] = p_temp;
+ }
+ }
+}
+