2 * This file is part of MPlayer.
4 * MPlayer is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * MPlayer is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
36 play_tree_is_valid(play_tree_t
* pt
);
40 play_tree_t
* r
= calloc(1,sizeof(play_tree_t
));
42 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",(int)sizeof(play_tree_t
));
45 r
->entry_type
= PLAY_TREE_ENTRY_NODE
;
50 play_tree_free(play_tree_t
* pt
, int children
) {
58 for(iter
= pt
->child
; iter
!= NULL
; ) {
59 play_tree_t
* nxt
=iter
->next
;
60 play_tree_free(iter
,1);
66 play_tree_remove(pt
,0,0);
68 for(iter
= pt
->child
; iter
!= NULL
; iter
= iter
->next
)
71 //if(pt->params) free(pt->params);
74 for(i
= 0 ; pt
->files
[i
] != NULL
; i
++)
83 play_tree_free_list(play_tree_t
* pt
, int children
) {
90 for(iter
= pt
; iter
->prev
!= NULL
; iter
= iter
->prev
)
94 play_tree_t
* nxt
= iter
->next
;
95 play_tree_free(iter
, children
);
103 play_tree_append_entry(play_tree_t
* pt
, play_tree_t
* entry
) {
108 assert(entry
!= NULL
);
114 for(iter
= pt
; iter
->next
!= NULL
; iter
= iter
->next
)
117 entry
->parent
= iter
->parent
;
124 play_tree_prepend_entry(play_tree_t
* pt
, play_tree_t
* entry
) {
129 assert(entry
!= NULL
);
132 for(iter
= pt
; iter
->prev
!= NULL
; iter
= iter
->prev
)
137 entry
->parent
= iter
->parent
;
142 assert(entry
->parent
->child
== iter
);
144 entry
->parent
->child
= entry
;
149 play_tree_insert_entry(play_tree_t
* pt
, play_tree_t
* entry
) {
153 assert(entry
!= NULL
);
156 entry
->parent
= pt
->parent
;
160 assert(pt
->next
->prev
== pt
);
162 entry
->next
= pt
->next
;
163 entry
->next
->prev
= entry
;
171 play_tree_remove(play_tree_t
* pt
, int free_it
, int with_children
) {
178 if(pt
->prev
&& pt
->next
) {
180 assert(pt
->prev
->next
== pt
);
181 assert(pt
->next
->prev
== pt
);
183 pt
->prev
->next
= pt
->next
;
184 pt
->next
->prev
= pt
->prev
;
188 assert(pt
->prev
->next
== pt
);
190 pt
->prev
->next
= NULL
;
191 } // Beginning of list
194 assert(pt
->next
->prev
== pt
);
196 pt
->next
->prev
= NULL
;
199 assert(pt
->parent
->child
== pt
);
201 pt
->parent
->child
= pt
->next
;
204 else if(pt
->parent
) {
206 assert(pt
->parent
->child
== pt
);
208 pt
->parent
->child
= NULL
;
211 pt
->prev
= pt
->next
= pt
->parent
= NULL
;
213 play_tree_free(pt
,with_children
);
218 play_tree_set_child(play_tree_t
* pt
, play_tree_t
* child
) {
223 assert(pt
->entry_type
== PLAY_TREE_ENTRY_NODE
);
226 //DEBUG_FF: Where are the children freed?
227 // Attention in using this function!
228 for(iter
= pt
->child
; iter
!= NULL
; iter
= iter
->next
)
231 // Go back to first one
232 for(iter
= child
; iter
->prev
!= NULL
; iter
= iter
->prev
)
237 for( ; iter
!= NULL
; iter
= iter
->next
)
243 play_tree_set_parent(play_tree_t
* pt
, play_tree_t
* parent
) {
251 pt
->parent
->child
= NULL
;
253 for(iter
= pt
; iter
!= NULL
; iter
= iter
->next
)
254 iter
->parent
= parent
;
257 for(iter
= pt
->prev
; iter
->prev
!= NULL
; iter
= iter
->prev
)
258 iter
->parent
= parent
;
259 iter
->parent
= parent
;
260 parent
->child
= iter
;
268 play_tree_add_file(play_tree_t
* pt
,char* file
) {
274 assert(pt
->child
== NULL
);
275 assert(file
!= NULL
);
278 if(pt
->entry_type
!= PLAY_TREE_ENTRY_NODE
&&
279 pt
->entry_type
!= PLAY_TREE_ENTRY_FILE
)
283 for(n
= 0 ; pt
->files
[n
] != NULL
; n
++)
286 pt
->files
= realloc(pt
->files
, (n
+ 2) * sizeof(char*));
287 if(pt
->files
==NULL
) {
288 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",(n
+2)*(int)sizeof(char*));
292 e
= pt
->files
[n
] = strdup(file
);
293 pt
->files
[n
+1] = NULL
;
295 pt
->entry_type
= PLAY_TREE_ENTRY_FILE
;
300 play_tree_remove_file(play_tree_t
* pt
,char* file
) {
305 assert(file
!= NULL
);
306 assert(pt
->entry_type
!= PLAY_TREE_ENTRY_NODE
);
309 for(n
=0 ; pt
->files
[n
] != NULL
; n
++) {
310 if(strcmp(file
,pt
->files
[n
]) == 0)
314 if(f
< 0) // Not found
324 memmove(&pt
->files
[f
],&pt
->files
[f
+1],(n
-f
)*sizeof(char*));
325 pt
->files
= realloc(pt
->files
, n
* sizeof(char*));
326 if(pt
->files
== NULL
) {
327 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",(n
+2)*(int)sizeof(char*));
339 play_tree_set_param(play_tree_t
* pt
, char* name
, char* val
) {
344 assert(name
!= NULL
);
348 for ( ; pt
->params
[n
].name
!= NULL
; n
++ ) { }
350 pt
->params
= realloc(pt
->params
, (n
+ 2) * sizeof(play_tree_param_t
));
351 if(pt
->params
== NULL
) {
352 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't realloc params (%d bytes of memory)\n",(n
+2)*(int)sizeof(play_tree_param_t
));
355 pt
->params
[n
].name
= strdup(name
);
356 pt
->params
[n
].value
= val
!= NULL
? strdup(val
) : NULL
;
357 memset(&pt
->params
[n
+1],0,sizeof(play_tree_param_t
));
363 play_tree_unset_param(play_tree_t
* pt
, char* name
) {
368 assert(name
!= NULL
);
369 assert(pt
->params
!= NULL
);
372 for(n
= 0 ; pt
->params
[n
].name
!= NULL
; n
++) {
373 if(strcasecmp(pt
->params
[n
].name
,name
) == 0)
380 if(pt
->params
[ni
].name
) free(pt
->params
[ni
].name
);
381 if(pt
->params
[ni
].value
) free(pt
->params
[ni
].value
);
384 memmove(&pt
->params
[ni
],&pt
->params
[ni
+1],(n
-ni
)*sizeof(play_tree_param_t
));
385 pt
->params
= realloc(pt
->params
, n
* sizeof(play_tree_param_t
));
386 if(pt
->params
== NULL
) {
387 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",n
*(int)sizeof(play_tree_param_t
));
399 play_tree_set_params_from(play_tree_t
* dest
,play_tree_t
* src
) {
403 assert(dest
!= NULL
);
410 for(i
= 0; src
->params
[i
].name
!= NULL
; i
++)
411 play_tree_set_param(dest
,src
->params
[i
].name
,src
->params
[i
].value
);
412 if(src
->flags
& PLAY_TREE_RND
) // pass the random flag too
413 dest
->flags
|= PLAY_TREE_RND
;
417 // all children if deep < 0
419 play_tree_set_flag(play_tree_t
* pt
, int flags
, int deep
) {
424 if(deep
&& pt
->child
) {
426 for(i
= pt
->child
; i
; i
= i
->next
)
427 play_tree_set_flag(i
,flags
,deep
);
432 play_tree_unset_flag(play_tree_t
* pt
, int flags
, int deep
) {
437 if(deep
&& pt
->child
) {
439 for(i
= pt
->child
; i
; i
= i
->next
)
440 play_tree_unset_flag(i
,flags
,deep
);
445 //////////////////////////////////// ITERATOR //////////////////////////////////////
448 play_tree_iter_push_params(play_tree_iter_t
* iter
) {
452 assert(iter
!= NULL
);
453 assert(iter
->config
!= NULL
);
454 assert(iter
->tree
!= NULL
);
459 // We always push a config because we can set some option
461 m_config_push(iter
->config
);
463 if(pt
->params
== NULL
)
467 for(n
= 0; pt
->params
[n
].name
!= NULL
; n
++) {
469 if((e
= m_config_set_option(iter
->config
,pt
->params
[n
].name
,pt
->params
[n
].value
)) < 0) {
470 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Error %d while setting option '%s' with value '%s'\n",e
,
471 pt
->params
[n
].name
,pt
->params
[n
].value
);
476 iter
->entry_pushed
= 1;
481 play_tree_iter_new(play_tree_t
* pt
,m_config_t
* config
) {
482 play_tree_iter_t
* iter
;
486 assert(config
!= NULL
);
489 if( ! play_tree_is_valid(pt
))
492 iter
= calloc(1,sizeof(play_tree_iter_t
));
494 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate new iterator (%d bytes of memory)\n",(int)sizeof(play_tree_iter_t
));
499 iter
->config
= config
;
502 iter
->loop
= pt
->parent
->loop
;
508 play_tree_iter_free(play_tree_iter_t
* iter
) {
511 assert(iter
!= NULL
);
514 if(iter
->status_stack
) {
516 assert(iter
->stack_size
> 0);
518 free(iter
->status_stack
);
525 play_tree_rnd_step(play_tree_t
* pt
) {
528 play_tree_t
*i
,*head
;
530 // Count how many free choice we have
531 for(i
= pt
; i
->prev
; i
= i
->prev
)
532 if(!(i
->flags
& PLAY_TREE_RND_PLAYED
)) count
++;
534 if(!(i
->flags
& PLAY_TREE_RND_PLAYED
)) count
++;
535 for(i
= pt
->next
; i
; i
= i
->next
)
536 if(!(i
->flags
& PLAY_TREE_RND_PLAYED
)) count
++;
538 if(!count
) return NULL
;
540 r
= (int)((float)(count
) * rand() / (RAND_MAX
+ 1.0));
542 for(i
= head
; i
; i
=i
->next
) {
543 if(!(i
->flags
& PLAY_TREE_RND_PLAYED
)) r
--;
547 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Random stepping error\n");
553 play_tree_iter_step(play_tree_iter_t
* iter
, int d
,int with_nodes
) {
556 if ( !iter
) return PLAY_TREE_ITER_ENTRY
;
557 if ( !iter
->root
) return PLAY_TREE_ITER_ENTRY
;
560 assert(iter
!= NULL
);
561 assert(iter
->root
!= NULL
);
562 //printf("PT : Stepping = %d\n",d);
565 if(iter
->tree
== NULL
) {
566 iter
->tree
= iter
->root
;
567 return play_tree_iter_step(iter
,0,with_nodes
);
570 if(iter
->config
&& iter
->entry_pushed
> 0) {
571 iter
->entry_pushed
= 0;
572 m_config_pop(iter
->config
);
575 if(iter
->tree
->parent
&& (iter
->tree
->parent
->flags
& PLAY_TREE_RND
))
576 iter
->mode
= PLAY_TREE_ITER_RND
;
578 iter
->mode
= PLAY_TREE_ITER_NORMAL
;
581 if(iter
->mode
== PLAY_TREE_ITER_RND
)
582 pt
= play_tree_rnd_step(iter
->tree
);
586 for(i
= d
; i
> 0 && pt
; i
--)
592 for(i
= d
; i
< 0 && pt
; i
++)
598 if(pt
== NULL
) { // No next
600 if (iter
->mode
== PLAY_TREE_ITER_RND
) {
601 if (iter
->root
->loop
== 0)
602 return PLAY_TREE_ITER_END
;
603 play_tree_unset_flag(iter
->root
, PLAY_TREE_RND_PLAYED
, -1);
604 if (iter
->root
->loop
> 0) iter
->root
->loop
--;
606 return play_tree_iter_step(iter
, 0, with_nodes
);
608 if(iter
->tree
->parent
&& iter
->tree
->parent
->loop
!= 0 && ((d
> 0 && iter
->loop
!= 0) || ( d
< 0 && (iter
->loop
< 0 || iter
->loop
< iter
->tree
->parent
->loop
) ) ) ) {
609 if(d
> 0) { // Go back to the first one
610 for(pt
= iter
->tree
; pt
->prev
!= NULL
; pt
= pt
->prev
)
612 if(iter
->loop
> 0) iter
->loop
--;
613 } else if( d
< 0 ) { // Or the last one
614 for(pt
= iter
->tree
; pt
->next
!= NULL
; pt
= pt
->next
)
616 if(iter
->loop
>= 0 && iter
->loop
< iter
->tree
->parent
->loop
) iter
->loop
++;
619 return play_tree_iter_step(iter
,0,with_nodes
);
622 return play_tree_iter_up_step(iter
,d
,with_nodes
);
626 // Is there any valid child?
627 if(pt
->child
&& play_tree_is_valid(pt
->child
)) {
629 if(with_nodes
) { // Stop on the node
630 return PLAY_TREE_ITER_NODE
;
631 } else // Or follow it
632 return play_tree_iter_down_step(iter
,d
,with_nodes
);
635 // Is it a valid entry?
636 if(! play_tree_is_valid(pt
)) {
637 if(d
== 0) { // Can this happen ? FF: Yes!
638 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"What to do now ???? Infinite loop if we continue\n");
639 return PLAY_TREE_ITER_ERROR
;
640 } // Not a valid entry : go to next one
641 return play_tree_iter_step(iter
,d
,with_nodes
);
645 assert(pt
->files
!= NULL
);
650 for(d
= 0 ; iter
->tree
->files
[d
] != NULL
; d
++)
655 play_tree_iter_push_params(iter
);
656 iter
->entry_pushed
= 1;
657 if(iter
->mode
== PLAY_TREE_ITER_RND
)
658 pt
->flags
|= PLAY_TREE_RND_PLAYED
;
661 return PLAY_TREE_ITER_ENTRY
;
666 play_tree_is_valid(play_tree_t
* pt
) {
673 if(pt
->entry_type
!= PLAY_TREE_ENTRY_NODE
) {
675 assert(pt
->child
== NULL
);
679 else if (pt
->child
!= NULL
) {
680 for(iter
= pt
->child
; iter
!= NULL
; iter
= iter
->next
) {
681 if(play_tree_is_valid(iter
))
689 play_tree_iter_up_step(play_tree_iter_t
* iter
, int d
,int with_nodes
) {
692 assert(iter
!= NULL
);
693 assert(iter
->tree
!= NULL
);
694 //printf("PT : Go UP\n");
698 if(iter
->tree
->parent
== iter
->root
->parent
)
699 return PLAY_TREE_ITER_END
;
702 assert(iter
->tree
->parent
!= NULL
);
703 assert(iter
->stack_size
> 0);
704 assert(iter
->status_stack
!= NULL
);
708 iter
->loop
= iter
->status_stack
[iter
->stack_size
];
709 if(iter
->stack_size
> 0)
710 iter
->status_stack
= realloc(iter
->status_stack
, iter
->stack_size
* sizeof(int));
712 free(iter
->status_stack
);
713 iter
->status_stack
= NULL
;
715 if(iter
->stack_size
> 0 && iter
->status_stack
== NULL
) {
716 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",iter
->stack_size
*(int)sizeof(char*));
717 return PLAY_TREE_ITER_ERROR
;
719 iter
->tree
= iter
->tree
->parent
;
721 // Pop subtree params
723 m_config_pop(iter
->config
);
724 if(iter
->mode
== PLAY_TREE_ITER_RND
)
725 iter
->tree
->flags
|= PLAY_TREE_RND_PLAYED
;
728 return play_tree_iter_step(iter
,d
,with_nodes
);
732 play_tree_iter_down_step(play_tree_iter_t
* iter
, int d
,int with_nodes
) {
735 assert(iter
->tree
->files
== NULL
);
736 assert(iter
->tree
->child
!= NULL
);
737 assert(iter
->tree
->child
->parent
== iter
->tree
);
738 //printf("PT : Go DOWN\n");
743 // Push subtree params
745 play_tree_iter_push_params(iter
);
748 iter
->status_stack
= realloc(iter
->status_stack
, iter
->stack_size
* sizeof(int));
749 if(iter
->status_stack
== NULL
) {
750 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",iter
->stack_size
*(int)sizeof(int));
751 return PLAY_TREE_ITER_ERROR
;
753 iter
->status_stack
[iter
->stack_size
-1] = iter
->loop
;
755 iter
->loop
= iter
->tree
->loop
-1;
757 iter
->tree
= iter
->tree
->child
;
760 for(pt
= iter
->tree
->child
; pt
->next
!= NULL
; pt
= pt
->next
)
765 return play_tree_iter_step(iter
,0,with_nodes
);
769 play_tree_iter_get_file(play_tree_iter_t
* iter
, int d
) {
771 assert(iter
!= NULL
);
772 assert(iter
->tree
->child
== NULL
);
775 if(iter
->tree
->files
== NULL
)
779 assert(iter
->num_files
> 0);
782 if(iter
->file
>= iter
->num_files
-1 || iter
->file
< -1)
786 if(iter
->file
>= iter
->num_files
- 1)
792 iter
->file
= iter
->num_files
- 1;
796 return iter
->tree
->files
[iter
->file
];
800 play_tree_cleanup(play_tree_t
* pt
) {
801 play_tree_t
* iter
, *tmp
, *first
;
807 if( ! play_tree_is_valid(pt
)) {
808 play_tree_remove(pt
,1,1);
814 for(iter
= pt
->child
; iter
!= NULL
; ) {
817 if(! play_tree_is_valid(tmp
)) {
818 play_tree_remove(tmp
,1,1);
819 if(tmp
== first
) first
= iter
;
823 for(iter
= first
; iter
!= NULL
; ) {
826 play_tree_cleanup(tmp
);
834 play_tree_iter_new_copy(play_tree_iter_t
* old
) {
835 play_tree_iter_t
* iter
;
841 iter
= malloc(sizeof(play_tree_iter_t
));
843 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",(int)sizeof(play_tree_iter_t
));
847 memcpy(iter
,old
,sizeof(play_tree_iter_t
));
848 if(old
->status_stack
) {
849 iter
->status_stack
= malloc(old
->stack_size
* sizeof(int));
850 if(iter
->status_stack
== NULL
) {
851 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",old
->stack_size
* (int)sizeof(int));
855 memcpy(iter
->status_stack
,old
->status_stack
,iter
->stack_size
*sizeof(int));
862 // HIGH Level API, by Fabian Franz (mplayer@fabian-franz.de)
864 play_tree_iter_t
* pt_iter_create(play_tree_t
** ppt
, m_config_t
* config
)
866 play_tree_iter_t
* r
=NULL
;
871 *ppt
=play_tree_cleanup(*ppt
);
874 r
= play_tree_iter_new(*ppt
,config
);
875 if (r
&& play_tree_iter_step(r
,0,0) != PLAY_TREE_ITER_ENTRY
)
877 play_tree_iter_free(r
);
885 void pt_iter_destroy(play_tree_iter_t
** iter
)
894 char* pt_iter_get_file(play_tree_iter_t
* iter
, int d
)
902 r
= play_tree_iter_get_file(iter
,d
);
906 if (play_tree_iter_step(iter
,d
,0) != PLAY_TREE_ITER_ENTRY
)
908 r
=play_tree_iter_get_file(iter
,d
);
915 void pt_iter_insert_entry(play_tree_iter_t
* iter
, play_tree_t
* entry
)
917 play_tree_t
*pt
= iter
->tree
;
924 play_tree_insert_entry(pt
, entry
);
925 play_tree_set_params_from(entry
,pt
);
928 void pt_iter_replace_entry(play_tree_iter_t
* iter
, play_tree_t
* entry
)
930 play_tree_t
*pt
= iter
->tree
;
932 pt_iter_insert_entry(iter
, entry
);
933 play_tree_remove(pt
, 1, 1);
937 //Add a new file as a new entry
938 void pt_add_file(play_tree_t
** ppt
, char* filename
)
940 play_tree_t
*pt
= *ppt
, *entry
= play_tree_new();
945 play_tree_add_file(entry
, filename
);
947 play_tree_append_entry(pt
, entry
);
953 play_tree_set_params_from(entry
,pt
);
956 void pt_add_gui_file(play_tree_t
** ppt
, char* path
, char* file
)
958 char* wholename
= malloc(strlen(path
)+strlen(file
)+2);
962 strcpy(wholename
, path
);
963 strcat(wholename
, "/");
964 strcat(wholename
, file
);
965 pt_add_file(ppt
, wholename
);
966 free(wholename
); // As pt_add_file strdups it anyway!
970 void pt_iter_goto_head(play_tree_iter_t
* iter
)
972 iter
->tree
=iter
->root
;
973 play_tree_iter_step(iter
, 0, 0);