]> git.sesse.net Git - vlc/blob - src/playlist/sort.c
34e69737e3e3817ac6660038dcc3f246a41df32d
[vlc] / src / playlist / sort.c
1 /*****************************************************************************
2  * sort.c : Playlist sorting functions
3  *****************************************************************************
4  * Copyright (C) 1999-2007 the VideoLAN team
5  * $Id$
6  *
7  * Authors: ClĂ©ment Stenac <zorglub@videolan.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 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include <vlc/vlc.h>
28 #include "vlc_playlist.h"
29 #include "playlist_internal.h"
30
31
32 static int playlist_ItemArraySort( playlist_t *p_playlist, int i_items,
33                                    playlist_item_t **pp_items, int i_mode,
34                                    int i_type );
35
36 /**
37  * Sort a node.
38  * This function must be entered with the playlist lock !
39  *
40  * \param p_playlist the playlist
41  * \param p_node the node to sort
42  * \param i_mode: SORT_ID, SORT_TITLE, SORT_ARTIST, SORT_ALBUM, SORT_RANDOM
43  * \param i_type: ORDER_NORMAL or ORDER_REVERSE (reversed order)
44  * \return VLC_SUCCESS on success
45  */
46 static int playlist_NodeSort( playlist_t * p_playlist , playlist_item_t *p_node,
47                               int i_mode, int i_type )
48 {
49     playlist_ItemArraySort( p_playlist,p_node->i_children,
50                             p_node->pp_children, i_mode, i_type );
51     return VLC_SUCCESS;
52 }
53
54 /**
55  * Sort a node recursively.
56  *
57  * This function must be entered with the playlist lock !
58  *
59  * \param p_playlist the playlist
60  * \param p_node the node to sort
61  * \param i_mode: SORT_ID, SORT_TITLE, SORT_ARTIST, SORT_ALBUM, SORT_RANDOM
62  * \param i_type: ORDER_NORMAL or ORDER_REVERSE (reversed order)
63  * \return VLC_SUCCESS on success
64  */
65 int playlist_RecursiveNodeSort( playlist_t *p_playlist, playlist_item_t *p_node,
66                                 int i_mode, int i_type )
67 {
68     int i;
69     playlist_NodeSort( p_playlist, p_node, i_mode, i_type );
70     for( i = 0 ; i< p_node->i_children; i++ )
71     {
72         if( p_node->pp_children[i]->i_children != -1 )
73         {
74             playlist_RecursiveNodeSort( p_playlist, p_node->pp_children[i],
75                                         i_mode,i_type );
76         }
77     }
78     return VLC_SUCCESS;
79 }
80
81
82 static int playlist_ItemArraySort( playlist_t *p_playlist, int i_items,
83                                    playlist_item_t **pp_items, int i_mode,
84                                    int i_type )
85 {
86     int i , i_small , i_position;
87     playlist_item_t *p_temp;
88     vlc_value_t val;
89     val.b_bool = VLC_TRUE;
90
91     (void)p_playlist; // a bit surprising we don't need p_playlist!
92
93     if( i_mode == SORT_RANDOM )
94     {
95         for( i_position = 0; i_position < i_items ; i_position ++ )
96         {
97             int i_new;
98
99             if( i_items > 1 )
100                 i_new = rand() % (i_items - 1);
101             else
102                 i_new = 0;
103             p_temp = pp_items[i_position];
104             pp_items[i_position] = pp_items[i_new];
105             pp_items[i_new] = p_temp;
106         }
107
108         return VLC_SUCCESS;
109     }
110
111 #define META_STRCASECMP_NAME( i, i_small ) { \
112     char *psz_i = input_item_GetName( pp_items[i]->p_input ); \
113     char *psz_ismall = input_item_GetName( pp_items[i_small]->p_input ); \
114     i_test = strcasecmp( psz_i, psz_ismall ); \
115     free( psz_i ); \
116     free( psz_ismall ); \
117 }
118
119
120 #define DO_META_SORT_ADV( node, integer ) { \
121     char *psz_a = input_item_GetMeta( pp_items[i]->p_input, vlc_meta_##node ); \
122     char *psz_b = input_item_GetMeta( pp_items[i_small]->p_input, vlc_meta_##node ); \
123     /* Nodes go first */ \
124     if( pp_items[i]->i_children == -1 && pp_items[i_small]->i_children >= 0 ) \
125         i_test = 1;\
126     else if( pp_items[i]->i_children >= 0 &&\
127              pp_items[i_small]->i_children == -1 ) \
128        i_test = -1; \
129     /* Both are nodes, sort by name */ \
130     else if( pp_items[i]->i_children >= 0 && \
131                pp_items[i_small]->i_children >= 0 ) \
132     { \
133         META_STRCASECMP_NAME( i, i_small ) \
134     } \
135     /* Both are items */ \
136     else if( psz_a == NULL && psz_b != NULL ) \
137         i_test = 1; \
138     else if( psz_a != NULL && psz_b == NULL ) \
139         i_test = -1;\
140     /* No meta, sort by name */ \
141     else if( psz_a == NULL && psz_b == NULL ) \
142     { \
143         META_STRCASECMP_NAME( i, i_small ); \
144     } \
145     else \
146     { \
147         if( !integer ) i_test = strcmp( psz_a, psz_b ); \
148         else           i_test = atoi( psz_a ) - atoi( psz_b ); \
149     } \
150     free( psz_a ); \
151     free( psz_b ); \
152 }
153 #define DO_META_SORT( node ) DO_META_SORT_ADV( node, VLC_FALSE )
154
155     for( i_position = 0; i_position < i_items -1 ; i_position ++ )
156     {
157         i_small  = i_position;
158         for( i = i_position + 1 ; i< i_items ; i++)
159         {
160             int i_test = 0;
161
162             if( i_mode == SORT_TITLE )
163             {
164                 META_STRCASECMP_NAME( i, i_small );
165             }
166             else if( i_mode == SORT_TITLE_NUMERIC )
167             {
168                 char *psz_i = input_item_GetName( pp_items[i]->p_input );
169                 char *psz_ismall =
170                         input_item_GetName( pp_items[i_small]->p_input );
171                 i_test = atoi( psz_i ) - atoi( psz_ismall );
172                 free( psz_i );
173                 free( psz_ismall );
174             }
175             else if( i_mode == SORT_DURATION )
176             {
177                 i_test = input_item_GetDuration( pp_items[i]->p_input ) -
178                          input_item_GetDuration( pp_items[i_small]->p_input );
179             }
180             else if( i_mode == SORT_ARTIST )
181             {
182                 DO_META_SORT( Artist );
183             }
184             else if( i_mode == SORT_GENRE )
185             {
186                 DO_META_SORT( Genre );
187             }
188             else if( i_mode == SORT_ALBUM )
189             {
190                 DO_META_SORT( Album );
191             }
192             else if( i_mode == SORT_TRACK_NUMBER )
193             {
194                 DO_META_SORT_ADV( TrackNumber, VLC_TRUE );
195             }
196             else if( i_mode == SORT_DESCRIPTION )
197             {
198                 DO_META_SORT( Description );
199             }
200             else if( i_mode == SORT_ID )
201             {
202                 i_test = pp_items[i]->i_id - pp_items[i_small]->i_id;
203             }
204             else if( i_mode == SORT_TITLE_NODES_FIRST )
205             {
206                 /* Alphabetic sort, all nodes first */
207
208                 if( pp_items[i]->i_children == -1 &&
209                     pp_items[i_small]->i_children >= 0 )
210                 {
211                     i_test = 1;
212                 }
213                 else if( pp_items[i]->i_children >= 0 &&
214                          pp_items[i_small]->i_children == -1 )
215                 {
216                     i_test = -1;
217                 }
218                 else
219                 {
220                     i_test = strcasecmp( pp_items[i]->p_input->psz_name,
221                                          pp_items[i_small]->p_input->psz_name );
222                 }
223             }
224
225             if( ( i_type == ORDER_NORMAL  && i_test < 0 ) ||
226                 ( i_type == ORDER_REVERSE && i_test > 0 ) )
227             {
228                 i_small = i;
229             }
230         }
231         p_temp = pp_items[i_position];
232         pp_items[i_position] = pp_items[i_small];
233         pp_items[i_small] = p_temp;
234     }
235 #undef DO_META_SORT
236 #undef DO_META_SORT_ADV
237
238     return VLC_SUCCESS;
239 }