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.
37 play_tree_is_valid(play_tree_t
* pt
);
41 play_tree_t
* r
= calloc(1,sizeof(play_tree_t
));
42 r
->entry_type
= PLAY_TREE_ENTRY_NODE
;
47 play_tree_free(play_tree_t
* pt
, int children
) {
53 for(iter
= pt
->child
; iter
!= NULL
; ) {
54 play_tree_t
* nxt
=iter
->next
;
55 play_tree_free(iter
,1);
61 play_tree_remove(pt
,0,0);
63 for(iter
= pt
->child
; iter
!= NULL
; iter
= iter
->next
)
66 talloc_free(pt
->params
);
70 for(i
= 0 ; pt
->files
[i
] != NULL
; i
++)
79 play_tree_free_list(play_tree_t
* pt
, int children
) {
84 for(iter
= pt
; iter
->prev
!= NULL
; iter
= iter
->prev
)
88 play_tree_t
* nxt
= iter
->next
;
89 play_tree_free(iter
, children
);
97 play_tree_append_entry(play_tree_t
* pt
, play_tree_t
* entry
) {
101 assert(entry
!= NULL
);
106 for(iter
= pt
; iter
->next
!= NULL
; iter
= iter
->next
)
109 entry
->parent
= iter
->parent
;
116 play_tree_prepend_entry(play_tree_t
* pt
, play_tree_t
* entry
) {
120 assert(entry
!= NULL
);
122 for(iter
= pt
; iter
->prev
!= NULL
; iter
= iter
->prev
)
127 entry
->parent
= iter
->parent
;
131 assert(entry
->parent
->child
== iter
);
132 entry
->parent
->child
= entry
;
137 play_tree_insert_entry(play_tree_t
* pt
, play_tree_t
* entry
) {
140 assert(entry
!= NULL
);
142 entry
->parent
= pt
->parent
;
145 assert(pt
->next
->prev
== pt
);
146 entry
->next
= pt
->next
;
147 entry
->next
->prev
= entry
;
155 play_tree_remove(play_tree_t
* pt
, int free_it
, int with_children
) {
160 if(pt
->prev
&& pt
->next
) {
161 assert(pt
->prev
->next
== pt
);
162 assert(pt
->next
->prev
== pt
);
163 pt
->prev
->next
= pt
->next
;
164 pt
->next
->prev
= pt
->prev
;
167 assert(pt
->prev
->next
== pt
);
168 pt
->prev
->next
= NULL
;
169 } // Beginning of list
171 assert(pt
->next
->prev
== pt
);
172 pt
->next
->prev
= NULL
;
174 assert(pt
->parent
->child
== pt
);
175 pt
->parent
->child
= pt
->next
;
178 else if(pt
->parent
) {
179 assert(pt
->parent
->child
== pt
);
180 pt
->parent
->child
= NULL
;
183 pt
->prev
= pt
->next
= pt
->parent
= NULL
;
185 play_tree_free(pt
,with_children
);
190 play_tree_set_child(play_tree_t
* pt
, play_tree_t
* child
) {
193 /* Roughly validate input data. Both, pt and child are going to be
194 * dereferenced, hence assure they're not NULL.
197 mp_msg(MSGT_PLAYTREE
, MSGL_ERR
, "Internal error, attempt to add an empty child or use empty playlist\n");
201 assert(pt
->entry_type
== PLAY_TREE_ENTRY_NODE
);
203 //DEBUG_FF: Where are the children freed?
204 // Attention in using this function!
205 for(iter
= pt
->child
; iter
!= NULL
; iter
= iter
->next
)
208 // Go back to first one
209 for(iter
= child
; iter
->prev
!= NULL
; iter
= iter
->prev
)
214 for( ; iter
!= NULL
; iter
= iter
->next
)
220 play_tree_set_parent(play_tree_t
* pt
, play_tree_t
* parent
) {
226 pt
->parent
->child
= NULL
;
228 for(iter
= pt
; iter
!= NULL
; iter
= iter
->next
)
229 iter
->parent
= parent
;
232 for(iter
= pt
->prev
; iter
->prev
!= NULL
; iter
= iter
->prev
)
233 iter
->parent
= parent
;
234 iter
->parent
= parent
;
235 parent
->child
= iter
;
243 play_tree_add_file(play_tree_t
* pt
,const char* file
) {
247 assert(pt
->child
== NULL
);
248 assert(file
!= NULL
);
250 if(pt
->entry_type
!= PLAY_TREE_ENTRY_NODE
&&
251 pt
->entry_type
!= PLAY_TREE_ENTRY_FILE
)
255 for(n
= 0 ; pt
->files
[n
] != NULL
; n
++)
258 pt
->files
= realloc(pt
->files
, (n
+ 2) * sizeof(char*));
259 if(pt
->files
==NULL
) {
260 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",(n
+2)*(int)sizeof(char*));
264 pt
->files
[n
] = strdup(file
);
265 pt
->files
[n
+1] = NULL
;
267 pt
->entry_type
= PLAY_TREE_ENTRY_FILE
;
272 play_tree_remove_file(play_tree_t
* pt
,const char* file
) {
276 assert(file
!= NULL
);
277 assert(pt
->entry_type
!= PLAY_TREE_ENTRY_NODE
);
279 for(n
=0 ; pt
->files
[n
] != NULL
; n
++) {
280 if(strcmp(file
,pt
->files
[n
]) == 0)
284 if(f
< 0) // Not found
290 memmove(&pt
->files
[f
],&pt
->files
[f
+1],(n
-f
)*sizeof(char*));
291 pt
->files
= realloc(pt
->files
, n
* sizeof(char*));
292 if(pt
->files
== NULL
) {
293 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",(n
+2)*(int)sizeof(char*));
305 play_tree_set_param(play_tree_t
* pt
, struct bstr name
, struct bstr val
) {
311 for ( ; pt
->params
[n
].name
!= NULL
; n
++ ) { }
313 pt
->params
= talloc_realloc(NULL
, pt
->params
, struct play_tree_param
, n
+ 2);
314 pt
->params
[n
].name
= bstrdup0(pt
->params
, name
);
315 pt
->params
[n
].value
= bstrdup0(pt
->params
, val
);
316 memset(&pt
->params
[n
+1],0,sizeof(play_tree_param_t
));
322 play_tree_unset_param(play_tree_t
* pt
, const char* name
) {
326 assert(name
!= NULL
);
327 assert(pt
->params
!= NULL
);
329 for(n
= 0 ; pt
->params
[n
].name
!= NULL
; n
++) {
330 if(strcasecmp(pt
->params
[n
].name
,name
) == 0)
337 talloc_free(pt
->params
[ni
].name
);
338 talloc_free(pt
->params
[ni
].value
);
341 memmove(&pt
->params
[ni
],&pt
->params
[ni
+1],(n
-ni
)*sizeof(play_tree_param_t
));
342 pt
->params
= talloc_realloc(NULL
, pt
->params
, struct play_tree_param
, n
);
344 talloc_free(pt
->params
);
352 play_tree_set_params_from(play_tree_t
* dest
,play_tree_t
* src
) {
355 assert(dest
!= NULL
);
361 for(i
= 0; src
->params
[i
].name
!= NULL
; i
++)
362 play_tree_set_param(dest
, bstr(src
->params
[i
].name
), bstr(src
->params
[i
].value
));
363 if(src
->flags
& PLAY_TREE_RND
) // pass the random flag too
364 dest
->flags
|= PLAY_TREE_RND
;
369 play_tree_unset_flag(play_tree_t
* pt
, int flags
, int deep
) {
374 if(deep
&& pt
->child
) {
376 for(i
= pt
->child
; i
; i
= i
->next
)
377 play_tree_unset_flag(i
,flags
,deep
);
382 //////////////////////////////////// ITERATOR //////////////////////////////////////
385 play_tree_iter_push_params(play_tree_iter_t
* iter
) {
388 assert(iter
->config
!= NULL
);
389 assert(iter
->tree
!= NULL
);
393 // We always push a config because we can set some option
395 m_config_push(iter
->config
);
397 if(pt
->params
== NULL
)
401 for(n
= 0; pt
->params
[n
].name
!= NULL
; n
++) {
403 if((e
= m_config_set_option0(iter
->config
, pt
->params
[n
].name
,
404 pt
->params
[n
].value
, false)) < 0) {
405 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Error %d while setting option '%s' with value '%s'\n",e
,
406 pt
->params
[n
].name
,pt
->params
[n
].value
);
411 iter
->entry_pushed
= 1;
415 play_tree_iter_new(play_tree_t
* pt
,m_config_t
* config
) {
416 play_tree_iter_t
* iter
;
419 assert(config
!= NULL
);
421 if( ! play_tree_is_valid(pt
))
424 iter
= calloc(1,sizeof(play_tree_iter_t
));
426 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate new iterator (%d bytes of memory)\n",(int)sizeof(play_tree_iter_t
));
431 iter
->config
= config
;
434 iter
->loop
= pt
->parent
->loop
;
440 play_tree_iter_free(play_tree_iter_t
* iter
) {
442 assert(iter
!= NULL
);
444 if(iter
->status_stack
) {
445 assert(iter
->stack_size
> 0);
446 free(iter
->status_stack
);
453 play_tree_rnd_step(play_tree_t
* pt
) {
456 play_tree_t
*i
,*head
;
458 // Count how many free choice we have
459 for(i
= pt
; i
->prev
; i
= i
->prev
)
460 if(!(i
->flags
& PLAY_TREE_RND_PLAYED
)) count
++;
462 if(!(i
->flags
& PLAY_TREE_RND_PLAYED
)) count
++;
463 for(i
= pt
->next
; i
; i
= i
->next
)
464 if(!(i
->flags
& PLAY_TREE_RND_PLAYED
)) count
++;
466 if(!count
) return NULL
;
468 r
= (int)((float)(count
) * rand() / (RAND_MAX
+ 1.0));
470 for(i
= head
; i
; i
=i
->next
) {
471 if(!(i
->flags
& PLAY_TREE_RND_PLAYED
)) r
--;
475 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Random stepping error\n");
481 play_tree_iter_step(play_tree_iter_t
* iter
, int d
,int with_nodes
) {
484 if ( !iter
) return PLAY_TREE_ITER_ENTRY
;
485 if ( !iter
->root
) return PLAY_TREE_ITER_ENTRY
;
487 assert(iter
!= NULL
);
488 assert(iter
->root
!= NULL
);
490 if(iter
->tree
== NULL
) {
491 iter
->tree
= iter
->root
;
492 return play_tree_iter_step(iter
,0,with_nodes
);
495 if(iter
->config
&& iter
->entry_pushed
> 0) {
496 iter
->entry_pushed
= 0;
497 m_config_pop(iter
->config
);
500 if(iter
->tree
->parent
&& (iter
->tree
->parent
->flags
& PLAY_TREE_RND
))
501 iter
->mode
= PLAY_TREE_ITER_RND
;
503 iter
->mode
= PLAY_TREE_ITER_NORMAL
;
506 if(iter
->mode
== PLAY_TREE_ITER_RND
)
507 pt
= play_tree_rnd_step(iter
->tree
);
511 for(i
= d
; i
> 0 && pt
; i
--)
517 for(i
= d
; i
< 0 && pt
; i
++)
523 if(pt
== NULL
) { // No next
525 if (iter
->mode
== PLAY_TREE_ITER_RND
) {
526 if (iter
->root
->loop
== 0)
527 return PLAY_TREE_ITER_END
;
528 play_tree_unset_flag(iter
->root
, PLAY_TREE_RND_PLAYED
, -1);
529 if (iter
->root
->loop
> 0) iter
->root
->loop
--;
531 return play_tree_iter_step(iter
, 0, with_nodes
);
533 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
) ) ) ) {
534 if(d
> 0) { // Go back to the first one
535 for(pt
= iter
->tree
; pt
->prev
!= NULL
; pt
= pt
->prev
)
537 if(iter
->loop
> 0) iter
->loop
--;
538 } else if( d
< 0 ) { // Or the last one
539 for(pt
= iter
->tree
; pt
->next
!= NULL
; pt
= pt
->next
)
541 if(iter
->loop
>= 0 && iter
->loop
< iter
->tree
->parent
->loop
) iter
->loop
++;
544 return play_tree_iter_step(iter
,0,with_nodes
);
547 return play_tree_iter_up_step(iter
,d
,with_nodes
);
551 // Is there any valid child?
552 if(pt
->child
&& play_tree_is_valid(pt
->child
)) {
554 if(with_nodes
) { // Stop on the node
555 return PLAY_TREE_ITER_NODE
;
556 } else // Or follow it
557 return play_tree_iter_down_step(iter
,d
,with_nodes
);
560 // Is it a valid entry?
561 if(! play_tree_is_valid(pt
)) {
562 if(d
== 0) { // Can this happen ? FF: Yes!
563 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"What to do now ???? Infinite loop if we continue\n");
564 return PLAY_TREE_ITER_ERROR
;
565 } // Not a valid entry : go to next one
566 return play_tree_iter_step(iter
,d
,with_nodes
);
569 assert(pt
->files
!= NULL
);
573 for(d
= 0 ; iter
->tree
->files
[d
] != NULL
; d
++)
578 play_tree_iter_push_params(iter
);
579 iter
->entry_pushed
= 1;
580 if(iter
->mode
== PLAY_TREE_ITER_RND
)
581 pt
->flags
|= PLAY_TREE_RND_PLAYED
;
584 return PLAY_TREE_ITER_ENTRY
;
589 play_tree_is_valid(play_tree_t
* pt
) {
592 if(pt
->entry_type
!= PLAY_TREE_ENTRY_NODE
) {
593 assert(pt
->child
== NULL
);
596 else if (pt
->child
!= NULL
) {
597 for(iter
= pt
->child
; iter
!= NULL
; iter
= iter
->next
) {
598 if(play_tree_is_valid(iter
))
606 play_tree_iter_up_step(play_tree_iter_t
* iter
, int d
,int with_nodes
) {
608 assert(iter
!= NULL
);
609 assert(iter
->tree
!= NULL
);
612 if(iter
->tree
->parent
== iter
->root
->parent
)
613 return PLAY_TREE_ITER_END
;
615 assert(iter
->tree
->parent
!= NULL
);
616 assert(iter
->stack_size
> 0);
617 assert(iter
->status_stack
!= NULL
);
620 iter
->loop
= iter
->status_stack
[iter
->stack_size
];
621 if(iter
->stack_size
> 0)
622 iter
->status_stack
= realloc(iter
->status_stack
, iter
->stack_size
* sizeof(int));
624 free(iter
->status_stack
);
625 iter
->status_stack
= NULL
;
627 if(iter
->stack_size
> 0 && iter
->status_stack
== NULL
) {
628 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",iter
->stack_size
*(int)sizeof(char*));
629 return PLAY_TREE_ITER_ERROR
;
631 iter
->tree
= iter
->tree
->parent
;
633 // Pop subtree params
635 m_config_pop(iter
->config
);
636 if(iter
->mode
== PLAY_TREE_ITER_RND
)
637 iter
->tree
->flags
|= PLAY_TREE_RND_PLAYED
;
640 return play_tree_iter_step(iter
,d
,with_nodes
);
644 play_tree_iter_down_step(play_tree_iter_t
* iter
, int d
,int with_nodes
) {
646 assert(iter
->tree
->files
== NULL
);
647 assert(iter
->tree
->child
!= NULL
);
648 assert(iter
->tree
->child
->parent
== iter
->tree
);
652 // Push subtree params
654 play_tree_iter_push_params(iter
);
657 iter
->status_stack
= realloc(iter
->status_stack
, iter
->stack_size
* sizeof(int));
658 if(iter
->status_stack
== NULL
) {
659 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",iter
->stack_size
*(int)sizeof(int));
660 return PLAY_TREE_ITER_ERROR
;
662 iter
->status_stack
[iter
->stack_size
-1] = iter
->loop
;
664 iter
->loop
= iter
->tree
->loop
-1;
666 iter
->tree
= iter
->tree
->child
;
669 for(pt
= iter
->tree
->child
; pt
->next
!= NULL
; pt
= pt
->next
)
674 return play_tree_iter_step(iter
,0,with_nodes
);
678 play_tree_iter_get_file(play_tree_iter_t
* iter
, int d
) {
679 assert(iter
!= NULL
);
680 assert(iter
->tree
->child
== NULL
);
682 if(iter
->tree
->files
== NULL
)
685 assert(iter
->num_files
> 0);
687 if(iter
->file
>= iter
->num_files
-1 || iter
->file
< -1)
691 if(iter
->file
>= iter
->num_files
- 1)
697 iter
->file
= iter
->num_files
- 1;
701 return iter
->tree
->files
[iter
->file
];
705 play_tree_cleanup(play_tree_t
* pt
) {
706 play_tree_t
* iter
, *tmp
, *first
;
710 if( ! play_tree_is_valid(pt
)) {
711 play_tree_remove(pt
,1,1);
717 for(iter
= pt
->child
; iter
!= NULL
; ) {
720 if(! play_tree_is_valid(tmp
)) {
721 play_tree_remove(tmp
,1,1);
722 if(tmp
== first
) first
= iter
;
726 for(iter
= first
; iter
!= NULL
; ) {
729 play_tree_cleanup(tmp
);
737 play_tree_iter_new_copy(play_tree_iter_t
* old
) {
738 play_tree_iter_t
* iter
;
742 iter
= malloc(sizeof(play_tree_iter_t
));
744 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",(int)sizeof(play_tree_iter_t
));
748 memcpy(iter
,old
,sizeof(play_tree_iter_t
));
749 if(old
->status_stack
) {
750 iter
->status_stack
= malloc(old
->stack_size
* sizeof(int));
751 if(iter
->status_stack
== NULL
) {
752 mp_msg(MSGT_PLAYTREE
,MSGL_ERR
,"Can't allocate %d bytes of memory\n",old
->stack_size
* (int)sizeof(int));
756 memcpy(iter
->status_stack
,old
->status_stack
,iter
->stack_size
*sizeof(int));
763 // HIGH Level API, by Fabian Franz (mplayer@fabian-franz.de)
765 play_tree_iter_t
* pt_iter_create(play_tree_t
** ppt
, m_config_t
* config
)
767 play_tree_iter_t
* r
=NULL
;
770 *ppt
=play_tree_cleanup(*ppt
);
773 r
= play_tree_iter_new(*ppt
,config
);
774 if (r
&& play_tree_iter_step(r
,0,0) != PLAY_TREE_ITER_ENTRY
)
776 play_tree_iter_free(r
);
784 void pt_iter_destroy(play_tree_iter_t
** iter
)
793 char* pt_iter_get_file(play_tree_iter_t
* iter
, int d
)
801 r
= play_tree_iter_get_file(iter
,d
);
805 if (play_tree_iter_step(iter
,d
,0) != PLAY_TREE_ITER_ENTRY
)
807 r
=play_tree_iter_get_file(iter
,d
);
814 void pt_iter_insert_entry(play_tree_iter_t
* iter
, play_tree_t
* entry
)
816 play_tree_t
*pt
= iter
->tree
;
821 play_tree_insert_entry(pt
, entry
);
822 play_tree_set_params_from(entry
,pt
);
825 void pt_iter_replace_entry(play_tree_iter_t
* iter
, play_tree_t
* entry
)
827 play_tree_t
*pt
= iter
->tree
;
829 pt_iter_insert_entry(iter
, entry
);
830 play_tree_remove(pt
, 1, 1);
834 //Add a new file as a new entry
835 void pt_add_file(play_tree_t
** ppt
, const char* filename
)
837 play_tree_t
*pt
= *ppt
, *entry
= play_tree_new();
839 play_tree_add_file(entry
, filename
);
841 play_tree_append_entry(pt
, entry
);
847 play_tree_set_params_from(entry
,pt
);
850 void pt_iter_goto_head(play_tree_iter_t
* iter
)
852 iter
->tree
=iter
->root
;
853 play_tree_iter_step(iter
, 0, 0);