19 play_tree_is_valid(play_tree_t
* pt
);
23 play_tree_t
* r
= calloc(1,sizeof(play_tree_t
));
25 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",(int)sizeof(play_tree_t
));
26 r
->entry_type
= PLAY_TREE_ENTRY_NODE
;
31 play_tree_free(play_tree_t
* pt
, int children
) {
39 for(iter
= pt
->child
; iter
!= NULL
; ) {
40 play_tree_t
* nxt
=iter
->next
;
41 play_tree_free(iter
,1);
47 play_tree_remove(pt
,0,0);
49 for(iter
= pt
->child
; iter
!= NULL
; iter
= iter
->next
)
52 //if(pt->params) free(pt->params);
55 for(i
= 0 ; pt
->files
[i
] != NULL
; i
++)
64 play_tree_free_list(play_tree_t
* pt
, int children
) {
71 for(iter
= pt
; iter
->prev
!= NULL
; iter
= iter
->prev
)
75 play_tree_t
* nxt
= iter
->next
;
76 play_tree_free(iter
, children
);
84 play_tree_append_entry(play_tree_t
* pt
, play_tree_t
* entry
) {
89 assert(entry
!= NULL
);
95 for(iter
= pt
; iter
->next
!= NULL
; iter
= iter
->next
)
98 entry
->parent
= iter
->parent
;
105 play_tree_prepend_entry(play_tree_t
* pt
, play_tree_t
* entry
) {
110 assert(entry
!= NULL
);
113 for(iter
= pt
; iter
->prev
!= NULL
; iter
= iter
->prev
)
118 entry
->parent
= iter
->parent
;
123 assert(entry
->parent
->child
== iter
);
125 entry
->parent
->child
= entry
;
130 play_tree_insert_entry(play_tree_t
* pt
, play_tree_t
* entry
) {
134 assert(entry
!= NULL
);
137 entry
->parent
= pt
->parent
;
141 assert(pt
->next
->prev
== pt
);
143 entry
->next
= pt
->next
;
144 entry
->next
->prev
= entry
;
152 play_tree_remove(play_tree_t
* pt
, int free_it
, int with_children
) {
159 if(pt
->prev
&& pt
->next
) {
161 assert(pt
->prev
->next
== pt
);
162 assert(pt
->next
->prev
== pt
);
164 pt
->prev
->next
= pt
->next
;
165 pt
->next
->prev
= pt
->prev
;
169 assert(pt
->prev
->next
== pt
);
171 pt
->prev
->next
= NULL
;
172 } // Beginning of list
175 assert(pt
->next
->prev
== pt
);
177 pt
->next
->prev
= NULL
;
180 assert(pt
->parent
->child
== pt
);
182 pt
->parent
->child
= pt
->next
;
185 else if(pt
->parent
) {
187 assert(pt
->parent
->child
== pt
);
189 pt
->parent
->child
= NULL
;
192 pt
->prev
= pt
->next
= pt
->parent
= NULL
;
194 play_tree_free(pt
,with_children
);
199 play_tree_set_child(play_tree_t
* pt
, play_tree_t
* child
) {
204 assert(pt
->entry_type
== PLAY_TREE_ENTRY_NODE
);
207 //DEBUG_FF: Where are the children freed?
208 // Attention in using this function!
209 for(iter
= pt
->child
; iter
!= NULL
; iter
= iter
->next
)
212 // Go back to first one
213 for(iter
= child
; iter
->prev
!= NULL
; iter
= iter
->prev
)
218 for( ; iter
!= NULL
; iter
= iter
->next
)
224 play_tree_set_parent(play_tree_t
* pt
, play_tree_t
* parent
) {
232 pt
->parent
->child
= NULL
;
234 for(iter
= pt
; iter
!= NULL
; iter
= iter
->next
)
235 iter
->parent
= parent
;
238 for(iter
= pt
->prev
; iter
->prev
!= NULL
; iter
= iter
->prev
)
239 iter
->parent
= parent
;
240 iter
->parent
= parent
;
241 parent
->child
= iter
;
249 play_tree_add_file(play_tree_t
* pt
,char* file
) {
255 assert(pt
->child
== NULL
);
256 assert(file
!= NULL
);
259 if(pt
->entry_type
!= PLAY_TREE_ENTRY_NODE
&&
260 pt
->entry_type
!= PLAY_TREE_ENTRY_FILE
)
264 for(n
= 0 ; pt
->files
[n
] != NULL
; n
++)
267 pt
->files
= (char**)realloc(pt
->files
,(n
+2)*sizeof(char*));
268 if(pt
->files
==NULL
) {
269 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",(n
+2)*(int)sizeof(char*));
273 e
= pt
->files
[n
] = strdup(file
);
274 pt
->files
[n
+1] = NULL
;
276 pt
->entry_type
= PLAY_TREE_ENTRY_FILE
;
281 play_tree_remove_file(play_tree_t
* pt
,char* file
) {
286 assert(file
!= NULL
);
287 assert(pt
->entry_type
!= PLAY_TREE_ENTRY_NODE
);
290 for(n
=0 ; pt
->files
[n
] != NULL
; n
++) {
291 if(strcmp(file
,pt
->files
[n
]) == 0)
295 if(f
< 0) // Not found
305 memmove(&pt
->files
[f
],&pt
->files
[f
+1],(n
-f
)*sizeof(char*));
306 pt
->files
= (char**)realloc(pt
->files
,n
*sizeof(char*));
307 if(pt
->files
== NULL
) {
308 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",(n
+2)*(int)sizeof(char*));
320 play_tree_set_param(play_tree_t
* pt
, char* name
, char* val
) {
325 assert(name
!= NULL
);
329 for( ; pt
->params
[n
].name
!= NULL
; n
++) {
330 if(strcasecmp(pt
->params
[n
].name
,name
) == 0)
336 if(pt
->params
[n
].value
!= NULL
) free(pt
->params
[n
].value
);
337 pt
->params
[n
].value
= val
!= NULL
? strdup(val
) : NULL
;
341 pt
->params
= (play_tree_param_t
*)realloc(pt
->params
,(n
+2)*sizeof(play_tree_param_t
));
342 if(pt
->params
== NULL
) {
343 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't realloc params (%d bytes of memory)\n",(n
+2)*(int)sizeof(play_tree_param_t
));
346 pt
->params
[n
].name
= strdup(name
);
347 pt
->params
[n
].value
= val
!= NULL
? strdup(val
) : NULL
;
348 memset(&pt
->params
[n
+1],0,sizeof(play_tree_param_t
));
354 play_tree_unset_param(play_tree_t
* pt
, char* name
) {
359 assert(name
!= NULL
);
360 assert(pt
->params
!= NULL
);
363 for(n
= 0 ; pt
->params
[n
].name
!= NULL
; n
++) {
364 if(strcasecmp(pt
->params
[n
].name
,name
) == 0)
371 if(pt
->params
[ni
].name
) free(pt
->params
[ni
].name
);
372 if(pt
->params
[ni
].value
) free(pt
->params
[ni
].value
);
375 memmove(&pt
->params
[ni
],&pt
->params
[ni
+1],(n
-ni
)*sizeof(play_tree_param_t
));
376 pt
->params
= (play_tree_param_t
*)realloc(pt
->params
,n
*sizeof(play_tree_param_t
));
377 if(pt
->params
== NULL
) {
378 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",n
*(int)sizeof(play_tree_param_t
));
390 play_tree_set_params_from(play_tree_t
* dest
,play_tree_t
* src
) {
394 assert(dest
!= NULL
);
401 for(i
= 0; src
->params
[i
].name
!= NULL
; i
++)
402 play_tree_set_param(dest
,src
->params
[i
].name
,src
->params
[i
].value
);
403 if(src
->flags
& PLAY_TREE_RND
) // pass the random flag too
404 dest
->flags
|= PLAY_TREE_RND
;
408 // all children if deep < 0
410 play_tree_set_flag(play_tree_t
* pt
, int flags
, int deep
) {
415 if(deep
&& pt
->child
) {
417 for(i
= pt
->child
; i
; i
= i
->next
)
418 play_tree_set_flag(i
,flags
,deep
);
423 play_tree_unset_flag(play_tree_t
* pt
, int flags
, int deep
) {
428 if(deep
&& pt
->child
) {
430 for(i
= pt
->child
; i
; i
= i
->next
)
431 play_tree_unset_flag(i
,flags
,deep
);
436 //////////////////////////////////// ITERATOR //////////////////////////////////////
439 play_tree_iter_push_params(play_tree_iter_t
* iter
) {
443 assert(iter
!= NULL
);
444 assert(iter
->config
!= NULL
);
445 assert(iter
->tree
!= NULL
);
450 // We always push a config because we can set some option
452 m_config_push(iter
->config
);
454 if(pt
->params
== NULL
)
458 for(n
= 0; pt
->params
[n
].name
!= NULL
; n
++) {
460 if((e
= m_config_set_option(iter
->config
,pt
->params
[n
].name
,pt
->params
[n
].value
)) < 0) {
461 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Error %d while setting option '%s' with value '%s'\n",e
,
462 pt
->params
[n
].name
,pt
->params
[n
].value
);
467 iter
->entry_pushed
= 1;
472 play_tree_iter_new(play_tree_t
* pt
,m_config_t
* config
) {
473 play_tree_iter_t
* iter
;
477 assert(config
!= NULL
);
480 if( ! play_tree_is_valid(pt
))
483 iter
= calloc(1,sizeof(play_tree_iter_t
));
485 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate new iterator (%d bytes of memory)\n",(int)sizeof(play_tree_iter_t
));
490 iter
->config
= config
;
493 iter
->loop
= pt
->parent
->loop
;
499 play_tree_iter_free(play_tree_iter_t
* iter
) {
502 assert(iter
!= NULL
);
505 if(iter
->status_stack
) {
507 assert(iter
->stack_size
> 0);
509 free(iter
->status_stack
);
516 play_tree_rnd_step(play_tree_t
* pt
) {
519 play_tree_t
*i
,*head
;
521 // Count how many free choice we have
522 for(i
= pt
; i
->prev
; i
= i
->prev
)
523 if(!(i
->flags
& PLAY_TREE_RND_PLAYED
)) count
++;
525 if(!(i
->flags
& PLAY_TREE_RND_PLAYED
)) count
++;
526 for(i
= pt
->next
; i
; i
= i
->next
)
527 if(!(i
->flags
& PLAY_TREE_RND_PLAYED
)) count
++;
529 if(!count
) return NULL
;
531 r
= (int)((float)(count
) * rand() / (RAND_MAX
+ 1.0));
533 for(i
= head
; i
; i
=i
->next
) {
534 if(!(i
->flags
& PLAY_TREE_RND_PLAYED
)) r
--;
538 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Random stepping error\n");
544 play_tree_iter_step(play_tree_iter_t
* iter
, int d
,int with_nodes
) {
547 if ( !iter
) return PLAY_TREE_ITER_ENTRY
;
548 if ( !iter
->root
) return PLAY_TREE_ITER_ENTRY
;
551 assert(iter
!= NULL
);
552 assert(iter
->root
!= NULL
);
553 //printf("PT : Stepping = %d\n",d);
556 if(iter
->tree
== NULL
) {
557 iter
->tree
= iter
->root
;
558 return play_tree_iter_step(iter
,0,with_nodes
);
561 if(iter
->config
&& iter
->entry_pushed
> 0) {
562 iter
->entry_pushed
= 0;
563 m_config_pop(iter
->config
);
566 if(iter
->tree
->parent
&& (iter
->tree
->parent
->flags
& PLAY_TREE_RND
))
567 iter
->mode
= PLAY_TREE_ITER_RND
;
569 iter
->mode
= PLAY_TREE_ITER_NORMAL
;
572 if(iter
->mode
== PLAY_TREE_ITER_RND
)
573 pt
= play_tree_rnd_step(iter
->tree
);
577 for(i
= d
; i
> 0 && pt
; i
--)
583 for(i
= d
; i
< 0 && pt
; i
++)
589 if(pt
== NULL
) { // No next
591 if (iter
->mode
== PLAY_TREE_ITER_RND
) {
592 if (iter
->root
->loop
== 0)
593 return PLAY_TREE_ITER_END
;
594 play_tree_unset_flag(iter
->root
, PLAY_TREE_RND_PLAYED
, -1);
595 if (iter
->root
->loop
> 0) iter
->root
->loop
--;
597 return play_tree_iter_step(iter
, 0, with_nodes
);
599 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
) ) ) ) {
600 if(d
> 0) { // Go back to the first one
601 for(pt
= iter
->tree
; pt
->prev
!= NULL
; pt
= pt
->prev
)
603 if(iter
->loop
> 0) iter
->loop
--;
604 } else if( d
< 0 ) { // Or the last one
605 for(pt
= iter
->tree
; pt
->next
!= NULL
; pt
= pt
->next
)
607 if(iter
->loop
>= 0 && iter
->loop
< iter
->tree
->parent
->loop
) iter
->loop
++;
610 return play_tree_iter_step(iter
,0,with_nodes
);
613 return play_tree_iter_up_step(iter
,d
,with_nodes
);
617 // Is there any valid child?
618 if(pt
->child
&& play_tree_is_valid(pt
->child
)) {
620 if(with_nodes
) { // Stop on the node
621 return PLAY_TREE_ITER_NODE
;
622 } else // Or follow it
623 return play_tree_iter_down_step(iter
,d
,with_nodes
);
626 // Is it a valid entry?
627 if(! play_tree_is_valid(pt
)) {
628 if(d
== 0) { // Can this happen ? FF: Yes!
629 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"What to do now ???? Infinite loop if we continue\n");
630 return PLAY_TREE_ITER_ERROR
;
631 } // Not a valid entry : go to next one
632 return play_tree_iter_step(iter
,d
,with_nodes
);
636 assert(pt
->files
!= NULL
);
641 for(d
= 0 ; iter
->tree
->files
[d
] != NULL
; d
++)
646 play_tree_iter_push_params(iter
);
647 iter
->entry_pushed
= 1;
648 if(iter
->mode
== PLAY_TREE_ITER_RND
)
649 pt
->flags
|= PLAY_TREE_RND_PLAYED
;
652 return PLAY_TREE_ITER_ENTRY
;
657 play_tree_is_valid(play_tree_t
* pt
) {
664 if(pt
->entry_type
!= PLAY_TREE_ENTRY_NODE
) {
666 assert(pt
->child
== NULL
);
670 else if (pt
->child
!= NULL
) {
671 for(iter
= pt
->child
; iter
!= NULL
; iter
= iter
->next
) {
672 if(play_tree_is_valid(iter
))
680 play_tree_iter_up_step(play_tree_iter_t
* iter
, int d
,int with_nodes
) {
683 assert(iter
!= NULL
);
684 assert(iter
->tree
!= NULL
);
685 //printf("PT : Go UP\n");
689 if(iter
->tree
->parent
== iter
->root
->parent
)
690 return PLAY_TREE_ITER_END
;
693 assert(iter
->tree
->parent
!= NULL
);
694 assert(iter
->stack_size
> 0);
695 assert(iter
->status_stack
!= NULL
);
699 iter
->loop
= iter
->status_stack
[iter
->stack_size
];
700 if(iter
->stack_size
> 0)
701 iter
->status_stack
= (int*)realloc(iter
->status_stack
,iter
->stack_size
*sizeof(int));
703 free(iter
->status_stack
);
704 iter
->status_stack
= NULL
;
706 if(iter
->stack_size
> 0 && iter
->status_stack
== NULL
) {
707 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",iter
->stack_size
*(int)sizeof(char*));
708 return PLAY_TREE_ITER_ERROR
;
710 iter
->tree
= iter
->tree
->parent
;
712 // Pop subtree params
714 m_config_pop(iter
->config
);
715 if(iter
->mode
== PLAY_TREE_ITER_RND
)
716 iter
->tree
->flags
|= PLAY_TREE_RND_PLAYED
;
719 return play_tree_iter_step(iter
,d
,with_nodes
);
723 play_tree_iter_down_step(play_tree_iter_t
* iter
, int d
,int with_nodes
) {
726 assert(iter
->tree
->files
== NULL
);
727 assert(iter
->tree
->child
!= NULL
);
728 assert(iter
->tree
->child
->parent
== iter
->tree
);
729 //printf("PT : Go DOWN\n");
734 // Push subtree params
736 play_tree_iter_push_params(iter
);
739 iter
->status_stack
= (int*)realloc(iter
->status_stack
,iter
->stack_size
*sizeof(int));
740 if(iter
->status_stack
== NULL
) {
741 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",iter
->stack_size
*(int)sizeof(int));
742 return PLAY_TREE_ITER_ERROR
;
744 iter
->status_stack
[iter
->stack_size
-1] = iter
->loop
;
746 iter
->loop
= iter
->tree
->loop
-1;
748 iter
->tree
= iter
->tree
->child
;
751 for(pt
= iter
->tree
->child
; pt
->next
!= NULL
; pt
= pt
->next
)
756 return play_tree_iter_step(iter
,0,with_nodes
);
760 play_tree_iter_get_file(play_tree_iter_t
* iter
, int d
) {
762 assert(iter
!= NULL
);
763 assert(iter
->tree
->child
== NULL
);
766 if(iter
->tree
->files
== NULL
)
770 assert(iter
->num_files
> 0);
773 if(iter
->file
>= iter
->num_files
-1 || iter
->file
< -1)
777 if(iter
->file
>= iter
->num_files
- 1)
783 iter
->file
= iter
->num_files
- 1;
787 return iter
->tree
->files
[iter
->file
];
791 play_tree_cleanup(play_tree_t
* pt
) {
792 play_tree_t
* iter
, *tmp
, *first
;
798 if( ! play_tree_is_valid(pt
)) {
799 play_tree_remove(pt
,1,1);
805 for(iter
= pt
->child
; iter
!= NULL
; ) {
808 if(! play_tree_is_valid(tmp
)) {
809 play_tree_remove(tmp
,1,1);
810 if(tmp
== first
) first
= iter
;
814 for(iter
= first
; iter
!= NULL
; ) {
817 play_tree_cleanup(tmp
);
825 play_tree_iter_new_copy(play_tree_iter_t
* old
) {
826 play_tree_iter_t
* iter
;
832 iter
= malloc(sizeof(play_tree_iter_t
));
834 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",(int)sizeof(play_tree_iter_t
));
838 memcpy(iter
,old
,sizeof(play_tree_iter_t
));
839 if(old
->status_stack
) {
840 iter
->status_stack
= malloc(old
->stack_size
* sizeof(int));
841 if(iter
->status_stack
== NULL
) {
842 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",old
->stack_size
* (int)sizeof(int));
846 memcpy(iter
->status_stack
,old
->status_stack
,iter
->stack_size
*sizeof(int));
853 // HIGH Level API, by Fabian Franz (mplayer@fabian-franz.de)
855 play_tree_iter_t
* pt_iter_create(play_tree_t
** ppt
, m_config_t
* config
)
857 play_tree_iter_t
* r
=NULL
;
862 *ppt
=play_tree_cleanup(*ppt
);
865 r
= play_tree_iter_new(*ppt
,config
);
866 if (r
&& play_tree_iter_step(r
,0,0) != PLAY_TREE_ITER_ENTRY
)
868 play_tree_iter_free(r
);
876 void pt_iter_destroy(play_tree_iter_t
** iter
)
885 char* pt_iter_get_file(play_tree_iter_t
* iter
, int d
)
893 r
= play_tree_iter_get_file(iter
,d
);
897 if (play_tree_iter_step(iter
,d
,0) != PLAY_TREE_ITER_ENTRY
)
899 r
=play_tree_iter_get_file(iter
,d
);
906 void pt_iter_insert_entry(play_tree_iter_t
* iter
, play_tree_t
* entry
)
908 play_tree_t
*pt
= iter
->tree
;
915 play_tree_insert_entry(pt
, entry
);
916 play_tree_set_params_from(entry
,pt
);
919 void pt_iter_replace_entry(play_tree_iter_t
* iter
, play_tree_t
* entry
)
921 play_tree_t
*pt
= iter
->tree
;
923 pt_iter_insert_entry(iter
, entry
);
924 play_tree_remove(pt
, 1, 1);
928 //Add a new file as a new entry
929 void pt_add_file(play_tree_t
** ppt
, char* filename
)
931 play_tree_t
*pt
= *ppt
, *entry
= play_tree_new();
936 play_tree_add_file(entry
, filename
);
938 play_tree_append_entry(pt
, entry
);
944 play_tree_set_params_from(entry
,pt
);
947 void pt_add_gui_file(play_tree_t
** ppt
, char* path
, char* file
)
949 char* wholename
= malloc(strlen(path
)+strlen(file
)+2);
953 strcpy(wholename
, path
);
954 strcat(wholename
, "/");
955 strcat(wholename
, file
);
956 pt_add_file(ppt
, wholename
);
957 free(wholename
); // As pt_add_file strdups it anyway!
961 void pt_iter_goto_head(play_tree_iter_t
* iter
)
963 iter
->tree
=iter
->root
;
964 play_tree_iter_step(iter
, 0, 0);