Update to MPlayer SVN rev 30589 and FFmpeg SVN rev 21847.
[vaapi:miks-mplayer.git] / playtree.c
1 /*
2  * This file is part of MPlayer.
3  *
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.
8  *
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.
13  *
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.
17  */
18
19 /// \file
20 /// \ingroup Playtree
21
22 #include "config.h"
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdio.h>
26 #include <unistd.h>
27 #include <errno.h>
28 #ifdef MP_DEBUG
29 #include <assert.h>
30 #endif
31 #include "m_config.h"
32 #include "playtree.h"
33 #include "mp_msg.h"
34
35 static int
36 play_tree_is_valid(play_tree_t* pt);
37
38 play_tree_t*
39 play_tree_new(void) {
40   play_tree_t* r = calloc(1,sizeof(play_tree_t));
41   if(r == NULL) {
42     mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",(int)sizeof(play_tree_t));
43     return NULL;
44   }
45   r->entry_type = PLAY_TREE_ENTRY_NODE;
46   return r;
47 }
48
49 void
50 play_tree_free(play_tree_t* pt, int children) {
51   play_tree_t* iter;
52
53 #ifdef MP_DEBUG
54   assert(pt != NULL);
55 #endif
56
57   if(children) {
58     for(iter = pt->child; iter != NULL; ) {
59       play_tree_t* nxt=iter->next;
60       play_tree_free(iter,1);
61       iter = nxt;
62     }
63     pt->child = NULL;
64   }
65
66   play_tree_remove(pt,0,0);
67
68   for(iter = pt->child ; iter != NULL ; iter = iter->next)
69     iter->parent = NULL;
70
71   //if(pt->params) free(pt->params);
72   if(pt->files) {
73     int i;
74     for(i = 0 ; pt->files[i] != NULL ; i++)
75       free(pt->files[i]);
76     free(pt->files);
77   }
78
79   free(pt);
80 }
81
82 void
83 play_tree_free_list(play_tree_t* pt, int children) {
84   play_tree_t* iter;
85
86 #ifdef MP_DEBUG
87   assert(pt != NULL);
88 #endif
89
90   for(iter = pt ; iter->prev != NULL ; iter = iter->prev)
91     /* NOTHING */;
92
93   while(iter) {
94     play_tree_t* nxt = iter->next;
95     play_tree_free(iter, children);
96     iter = nxt;
97   }
98
99
100 }
101
102 void
103 play_tree_append_entry(play_tree_t* pt, play_tree_t* entry) {
104   play_tree_t* iter;
105
106 #ifdef MP_DEBUG
107   assert(pt != NULL);
108   assert(entry != NULL);
109 #endif
110
111   if(pt == entry)
112     return;
113
114   for(iter = pt ; iter->next != NULL ; iter = iter->next)
115     /* NOTHING */;
116
117   entry->parent = iter->parent;
118   entry->prev = iter;
119   entry->next = NULL;
120   iter->next = entry;
121 }
122
123 void
124 play_tree_prepend_entry(play_tree_t* pt, play_tree_t* entry) {
125   play_tree_t* iter;
126
127 #ifdef MP_DEBUG
128   assert(pt != NULL);
129   assert(entry != NULL);
130 #endif
131
132   for(iter = pt ; iter->prev != NULL; iter = iter->prev)
133     /* NOTHING */;
134
135   entry->prev = NULL;
136   entry->next = iter;
137   entry->parent = iter->parent;
138
139   iter->prev = entry;
140   if(entry->parent) {
141 #ifdef MP_DEBUG
142     assert(entry->parent->child == iter);
143 #endif
144     entry->parent->child = entry;
145   }
146 }
147
148 void
149 play_tree_insert_entry(play_tree_t* pt, play_tree_t* entry) {
150
151 #ifdef MP_DEBUG
152   assert(pt != NULL);
153   assert(entry != NULL);
154 #endif
155
156   entry->parent = pt->parent;
157   entry->prev = pt;
158   if(pt->next) {
159 #ifdef MP_DEBUG
160     assert(pt->next->prev == pt);
161 #endif
162     entry->next = pt->next;
163     entry->next->prev = entry;
164   } else
165     entry->next = NULL;
166   pt->next = entry;
167
168 }
169
170 void
171 play_tree_remove(play_tree_t* pt, int free_it, int with_children) {
172
173 #ifdef MP_DEBUG
174   assert(pt != NULL);
175 #endif
176
177   // Middle of list
178   if(pt->prev && pt->next) {
179 #ifdef MP_DEBUG
180     assert(pt->prev->next == pt);
181     assert(pt->next->prev == pt);
182 #endif
183     pt->prev->next = pt->next;
184     pt->next->prev = pt->prev;
185   } // End of list
186   else if(pt->prev) {
187 #ifdef MP_DEBUG
188     assert(pt->prev->next == pt);
189 #endif
190     pt->prev->next = NULL;
191   } // Beginning of list
192   else if(pt->next) {
193 #ifdef MP_DEBUG
194     assert(pt->next->prev == pt);
195 #endif
196     pt->next->prev = NULL;
197     if(pt->parent) {
198 #ifdef MP_DEBUG
199       assert(pt->parent->child == pt);
200 #endif
201       pt->parent->child = pt->next;
202     }
203   } // The only one
204   else if(pt->parent) {
205 #ifdef MP_DEBUG
206     assert(pt->parent->child == pt);
207 #endif
208     pt->parent->child = NULL;
209   }
210
211   pt->prev = pt->next = pt->parent = NULL;
212   if(free_it)
213     play_tree_free(pt,with_children);
214
215 }
216
217 void
218 play_tree_set_child(play_tree_t* pt, play_tree_t* child) {
219   play_tree_t* iter;
220
221 #ifdef MP_DEBUG
222   assert(pt != NULL);
223   assert(pt->entry_type == PLAY_TREE_ENTRY_NODE);
224 #endif
225
226   //DEBUG_FF: Where are the children freed?
227   // Attention in using this function!
228   for(iter = pt->child ; iter != NULL ; iter = iter->next)
229     iter->parent = NULL;
230
231   // Go back to first one
232   for(iter = child ; iter->prev != NULL ; iter = iter->prev)
233     /* NOTHING */;
234
235   pt->child = iter;
236
237   for( ; iter != NULL ; iter= iter->next)
238     iter->parent = pt;
239
240 }
241
242 void
243 play_tree_set_parent(play_tree_t* pt, play_tree_t* parent) {
244   play_tree_t* iter;
245
246 #ifdef MP_DEBUG
247   assert(pt != NULL);
248 #endif
249
250   if(pt->parent)
251     pt->parent->child = NULL;
252
253   for(iter = pt ; iter != NULL ; iter = iter->next)
254     iter->parent = parent;
255
256   if(pt->prev) {
257     for(iter = pt->prev ; iter->prev != NULL ; iter = iter->prev)
258       iter->parent = parent;
259     iter->parent = parent;
260     parent->child = iter;
261   } else
262     parent->child = pt;
263
264 }
265
266
267 void
268 play_tree_add_file(play_tree_t* pt,char* file) {
269   int n = 0;
270   char* e;
271
272 #ifdef MP_DEBUG
273   assert(pt != NULL);
274   assert(pt->child == NULL);
275   assert(file != NULL);
276 #endif
277
278   if(pt->entry_type != PLAY_TREE_ENTRY_NODE &&
279      pt->entry_type != PLAY_TREE_ENTRY_FILE)
280     return;
281
282   if(pt->files) {
283     for(n = 0 ; pt->files[n] != NULL ; n++)
284       /* NOTHING */;
285   }
286   pt->files = (char**)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*));
289     return;
290   }
291
292   e = pt->files[n] = strdup(file);
293   pt->files[n+1] = NULL;
294
295   pt->entry_type = PLAY_TREE_ENTRY_FILE;
296
297 }
298
299 int
300 play_tree_remove_file(play_tree_t* pt,char* file) {
301   int n,f = -1;
302
303 #ifdef MP_DEBUG
304   assert(pt != NULL);
305   assert(file != NULL);
306   assert(pt->entry_type != PLAY_TREE_ENTRY_NODE);
307 #endif
308
309   for(n=0 ; pt->files[n] != NULL ; n++) {
310     if(strcmp(file,pt->files[n]) == 0)
311       f = n;
312   }
313
314   if(f < 0) // Not found
315     return 0;
316
317 #ifdef MP_DEBUG
318   assert(n > f);
319 #endif
320
321   free(pt->files[f]);
322
323   if(n > 1) {
324     memmove(&pt->files[f],&pt->files[f+1],(n-f)*sizeof(char*));
325     pt->files = (char**)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*));
328       return -1;
329     }
330   } else {
331     free(pt->files);
332     pt->files = NULL;
333   }
334
335   return 1;
336 }
337
338 void
339 play_tree_set_param(play_tree_t* pt, char* name, char* val) {
340   int n = 0;
341
342 #ifdef MP_DEBUG
343   assert(pt != NULL);
344   assert(name != NULL);
345 #endif
346
347   if(pt->params)
348     for ( ; pt->params[n].name != NULL ; n++ ) { }
349
350   pt->params = (play_tree_param_t*)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));
353       return;
354   }
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));
358
359   return;
360 }
361
362 int
363 play_tree_unset_param(play_tree_t* pt, char* name) {
364   int n,ni = -1;
365
366 #ifdef MP_DEBUG
367   assert(pt != NULL);
368   assert(name != NULL);
369   assert(pt->params != NULL);
370 #endif
371
372   for(n = 0 ; pt->params[n].name != NULL ; n++) {
373     if(strcasecmp(pt->params[n].name,name) == 0)
374       ni = n;
375   }
376
377   if(ni < 0)
378     return 0;
379
380   if(pt->params[ni].name) free(pt->params[ni].name);
381   if(pt->params[ni].value) free(pt->params[ni].value);
382
383   if(n > 1) {
384     memmove(&pt->params[ni],&pt->params[ni+1],(n-ni)*sizeof(play_tree_param_t));
385     pt->params = (play_tree_param_t*)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));
388       return -1;
389     }
390   } else {
391     free(pt->params);
392     pt->params = NULL;
393   }
394
395   return 1;
396 }
397
398 void
399 play_tree_set_params_from(play_tree_t* dest,play_tree_t* src) {
400   int i;
401
402 #ifdef MP_DEBUG
403   assert(dest != NULL);
404   assert(src != NULL);
405 #endif
406
407   if(!src->params)
408     return;
409
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;
414
415 }
416
417 // all children if deep < 0
418 void
419 play_tree_set_flag(play_tree_t* pt, int flags , int deep) {
420   play_tree_t*  i;
421
422   pt->flags |= flags;
423
424   if(deep && pt->child) {
425     if(deep > 0) deep--;
426     for(i = pt->child ; i ; i = i->next)
427       play_tree_set_flag(i,flags,deep);
428   }
429 }
430
431 void
432 play_tree_unset_flag(play_tree_t* pt, int flags , int deep) {
433   play_tree_t*  i;
434
435   pt->flags &= ~flags;
436
437   if(deep && pt->child) {
438     if(deep > 0) deep--;
439     for(i = pt->child ; i ; i = i->next)
440       play_tree_unset_flag(i,flags,deep);
441   }
442 }
443
444
445 //////////////////////////////////// ITERATOR //////////////////////////////////////
446
447 static void
448 play_tree_iter_push_params(play_tree_iter_t* iter) {
449   int n;
450   play_tree_t* pt;
451 #ifdef MP_DEBUG
452   assert(iter != NULL);
453   assert(iter->config != NULL);
454   assert(iter->tree != NULL);
455 #endif
456
457   pt = iter->tree;
458
459   // We always push a config because we can set some option
460   // while playing
461   m_config_push(iter->config);
462
463   if(pt->params == NULL)
464     return;
465
466
467   for(n = 0; pt->params[n].name != NULL ; n++) {
468     int e;
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);
472     }
473   }
474
475   if(!pt->child)
476     iter->entry_pushed = 1;
477   return;
478 }
479
480 play_tree_iter_t*
481 play_tree_iter_new(play_tree_t* pt,m_config_t* config) {
482   play_tree_iter_t* iter;
483
484 #ifdef MP_DEBUG
485   assert(pt != NULL);
486   assert(config != NULL);
487 #endif
488
489   if( ! play_tree_is_valid(pt))
490     return NULL;
491
492   iter = calloc(1,sizeof(play_tree_iter_t));
493   if(! iter) {
494       mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate new iterator (%d bytes of memory)\n",(int)sizeof(play_tree_iter_t));
495       return NULL;
496   }
497   iter->root = pt;
498   iter->tree = NULL;
499   iter->config = config;
500
501   if(pt->parent)
502     iter->loop = pt->parent->loop;
503
504   return iter;
505 }
506
507 void
508 play_tree_iter_free(play_tree_iter_t* iter) {
509
510 #ifdef MP_DEBUG
511   assert(iter != NULL);
512 #endif
513
514   if(iter->status_stack) {
515 #ifdef MP_DEBUG
516     assert(iter->stack_size > 0);
517 #endif
518     free(iter->status_stack);
519   }
520
521   free(iter);
522 }
523
524 static play_tree_t*
525 play_tree_rnd_step(play_tree_t* pt) {
526   int count = 0;
527   int r;
528   play_tree_t *i,*head;
529
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++;
533   head = i;
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++;
537
538   if(!count) return NULL;
539
540   r = (int)((float)(count) * rand() / (RAND_MAX + 1.0));
541
542   for(i = head ; i  ; i=i->next) {
543     if(!(i->flags & PLAY_TREE_RND_PLAYED)) r--;
544     if(r < 0) return i;
545   }
546
547   mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Random stepping error\n");
548   return NULL;
549 }
550
551
552 int
553 play_tree_iter_step(play_tree_iter_t* iter, int d,int with_nodes) {
554   play_tree_t* pt;
555
556   if ( !iter ) return PLAY_TREE_ITER_ENTRY;
557   if ( !iter->root ) return PLAY_TREE_ITER_ENTRY;
558
559 #ifdef MP_DEBUG
560   assert(iter != NULL);
561   assert(iter->root != NULL);
562   //printf("PT : Stepping = %d\n",d);
563 #endif
564
565   if(iter->tree == NULL) {
566     iter->tree = iter->root;
567     return play_tree_iter_step(iter,0,with_nodes);
568   }
569
570   if(iter->config && iter->entry_pushed > 0) {
571     iter->entry_pushed = 0;
572     m_config_pop(iter->config);
573   }
574
575   if(iter->tree->parent && (iter->tree->parent->flags & PLAY_TREE_RND))
576     iter->mode = PLAY_TREE_ITER_RND;
577   else
578     iter->mode = PLAY_TREE_ITER_NORMAL;
579
580   iter->file = -1;
581   if(iter->mode == PLAY_TREE_ITER_RND)
582     pt = play_tree_rnd_step(iter->tree);
583   else if( d > 0 ) {
584     int i;
585     pt = iter->tree;
586     for(i = d ; i > 0 && pt ; i--)
587       pt = pt->next;
588     d = i ? i : 1;
589   } else if(d < 0) {
590     int i;
591     pt = iter->tree;
592     for(i = d ; i < 0 && pt ; i++)
593       pt = pt->prev;
594     d = i ? i : -1;
595   } else
596     pt = iter->tree;
597
598   if(pt == NULL) { // No next
599     // Must we loop?
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--;
605       // try again
606       return play_tree_iter_step(iter, 0, with_nodes);
607     } else
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)
611           /* NOTHNG */;
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)
615           /* NOTHNG */;
616         if(iter->loop >= 0 && iter->loop < iter->tree->parent->loop) iter->loop++;
617       }
618       iter->tree = pt;
619       return play_tree_iter_step(iter,0,with_nodes);
620     }
621     // Go up one level
622     return play_tree_iter_up_step(iter,d,with_nodes);
623
624   }
625
626   // Is there any valid child?
627   if(pt->child && play_tree_is_valid(pt->child)) {
628     iter->tree = pt;
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);
633   }
634
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);
642   }
643
644 #ifdef MP_DEBUG
645   assert(pt->files != NULL);
646 #endif
647
648   iter->tree = pt;
649
650   for(d = 0 ; iter->tree->files[d] != NULL ; d++)
651     /* NOTHING */;
652   iter->num_files = d;
653
654   if(iter->config) {
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;
659   }
660
661   return PLAY_TREE_ITER_ENTRY;
662
663 }
664
665 static int
666 play_tree_is_valid(play_tree_t* pt) {
667   play_tree_t* iter;
668
669 #ifdef MP_DEBUG
670   assert(pt != NULL);
671 #endif
672
673   if(pt->entry_type != PLAY_TREE_ENTRY_NODE) {
674 #ifdef MP_DEBUG
675     assert(pt->child == NULL);
676 #endif
677     return 1;
678   }
679   else if (pt->child != NULL) {
680     for(iter = pt->child ; iter != NULL ; iter = iter->next) {
681       if(play_tree_is_valid(iter))
682         return 1;
683     }
684   }
685   return 0;
686 }
687
688 int
689 play_tree_iter_up_step(play_tree_iter_t* iter, int d,int with_nodes) {
690
691 #ifdef MP_DEBUG
692   assert(iter != NULL);
693   assert(iter->tree != NULL);
694   //printf("PT : Go UP\n");
695 #endif
696
697   iter->file = -1;
698   if(iter->tree->parent == iter->root->parent)
699     return PLAY_TREE_ITER_END;
700
701 #ifdef MP_DEBUG
702   assert(iter->tree->parent != NULL);
703   assert(iter->stack_size > 0);
704   assert(iter->status_stack != NULL);
705 #endif
706
707   iter->stack_size--;
708   iter->loop = iter->status_stack[iter->stack_size];
709   if(iter->stack_size > 0)
710     iter->status_stack = (int*)realloc(iter->status_stack,iter->stack_size*sizeof(int));
711   else {
712     free(iter->status_stack);
713     iter->status_stack = NULL;
714   }
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;
718   }
719   iter->tree = iter->tree->parent;
720
721   // Pop subtree params
722   if(iter->config) {
723     m_config_pop(iter->config);
724     if(iter->mode == PLAY_TREE_ITER_RND)
725       iter->tree->flags |= PLAY_TREE_RND_PLAYED;
726   }
727
728   return play_tree_iter_step(iter,d,with_nodes);
729 }
730
731 int
732 play_tree_iter_down_step(play_tree_iter_t* iter, int d,int with_nodes) {
733
734 #ifdef MP_DEBUG
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");
739 #endif
740
741   iter->file = -1;
742
743   //  Push subtree params
744   if(iter->config)
745     play_tree_iter_push_params(iter);
746
747   iter->stack_size++;
748   iter->status_stack = (int*)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;
752   }
753   iter->status_stack[iter->stack_size-1] = iter->loop;
754   // Set new status
755   iter->loop = iter->tree->loop-1;
756   if(d >= 0)
757     iter->tree = iter->tree->child;
758   else {
759     play_tree_t* pt;
760     for(pt = iter->tree->child ; pt->next != NULL ; pt = pt->next)
761       /*NOTING*/;
762     iter->tree = pt;
763   }
764
765   return play_tree_iter_step(iter,0,with_nodes);
766 }
767
768 char*
769 play_tree_iter_get_file(play_tree_iter_t* iter, int d) {
770 #ifdef MP_DEBUG
771   assert(iter != NULL);
772   assert(iter->tree->child == NULL);
773 #endif
774
775   if(iter->tree->files == NULL)
776     return NULL;
777
778 #ifdef MP_DEBUG
779   assert(iter->num_files > 0);
780 #endif
781
782   if(iter->file >= iter->num_files-1 || iter->file < -1)
783     return NULL;
784
785   if(d > 0) {
786     if(iter->file >= iter->num_files - 1)
787       iter->file = 0;
788     else
789       iter->file++;
790   } else if(d < 0) {
791     if(iter->file <= 0)
792       iter->file = iter->num_files - 1;
793     else
794       iter->file--;
795   }
796   return iter->tree->files[iter->file];
797 }
798
799 play_tree_t*
800 play_tree_cleanup(play_tree_t* pt) {
801   play_tree_t* iter, *tmp, *first;
802
803 #ifdef MP_DEBUG
804   assert(pt != NULL);
805 #endif
806
807   if( ! play_tree_is_valid(pt)) {
808     play_tree_remove(pt,1,1);
809     return NULL;
810   }
811
812   first = pt->child;
813
814   for(iter = pt->child ; iter != NULL ; ) {
815     tmp = iter;
816     iter = iter->next;
817     if(! play_tree_is_valid(tmp)) {
818       play_tree_remove(tmp,1,1);
819       if(tmp == first) first = iter;
820     }
821   }
822
823   for(iter = first ; iter != NULL ; ) {
824     tmp = iter;
825     iter = iter->next;
826     play_tree_cleanup(tmp);
827   }
828
829   return pt;
830
831 }
832
833 play_tree_iter_t*
834 play_tree_iter_new_copy(play_tree_iter_t* old) {
835   play_tree_iter_t* iter;
836
837 #ifdef MP_DEBUG
838   assert(old != NULL);
839 #endif
840
841   iter = malloc(sizeof(play_tree_iter_t));
842   if(iter == NULL) {
843     mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",(int)sizeof(play_tree_iter_t));
844     return NULL;
845   }
846 ;
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));
852       free(iter);
853       return NULL;
854     }
855     memcpy(iter->status_stack,old->status_stack,iter->stack_size*sizeof(int));
856   }
857   iter->config = NULL;
858
859   return iter;
860 }
861
862 // HIGH Level API, by Fabian Franz (mplayer@fabian-franz.de)
863 //
864 play_tree_iter_t* pt_iter_create(play_tree_t** ppt, m_config_t* config)
865 {
866   play_tree_iter_t* r=NULL;
867 #ifdef MP_DEBUG
868   assert(*ppt!=NULL);
869 #endif
870
871   *ppt=play_tree_cleanup(*ppt);
872
873   if(*ppt) {
874     r = play_tree_iter_new(*ppt,config);
875     if (r && play_tree_iter_step(r,0,0) != PLAY_TREE_ITER_ENTRY)
876     {
877       play_tree_iter_free(r);
878       r = NULL;
879     }
880   }
881
882   return r;
883 }
884
885 void pt_iter_destroy(play_tree_iter_t** iter)
886 {
887   if (iter && *iter)
888   {
889     free(*iter);
890     iter=NULL;
891   }
892 }
893
894 char* pt_iter_get_file(play_tree_iter_t* iter, int d)
895 {
896   int i=0;
897   char* r;
898
899   if (iter==NULL)
900     return NULL;
901
902   r = play_tree_iter_get_file(iter,d);
903
904   while (!r && d!=0)
905   {
906     if (play_tree_iter_step(iter,d,0) != PLAY_TREE_ITER_ENTRY)
907         break;
908     r=play_tree_iter_get_file(iter,d);
909     i++;
910   }
911
912   return r;
913 }
914
915 void pt_iter_insert_entry(play_tree_iter_t* iter, play_tree_t* entry)
916 {
917   play_tree_t *pt = iter->tree;
918 #ifdef MP_DEBUG
919   assert(pt!=NULL);
920   assert(entry!=NULL);
921   assert(entry!=pt);
922 #endif
923
924   play_tree_insert_entry(pt, entry);
925   play_tree_set_params_from(entry,pt);
926 }
927
928 void pt_iter_replace_entry(play_tree_iter_t* iter, play_tree_t* entry)
929 {
930   play_tree_t *pt = iter->tree;
931
932   pt_iter_insert_entry(iter, entry);
933   play_tree_remove(pt, 1, 1);
934   iter->tree=entry;
935 }
936
937 //Add a new file as a new entry
938 void pt_add_file(play_tree_t** ppt, char* filename)
939 {
940   play_tree_t *pt = *ppt, *entry = play_tree_new();
941 #ifdef MP_DEBUG
942   assert(entry!=NULL);
943 #endif
944
945   play_tree_add_file(entry, filename);
946   if (pt)
947     play_tree_append_entry(pt, entry);
948   else
949   {
950     pt=entry;
951     *ppt=pt;
952   }
953   play_tree_set_params_from(entry,pt);
954 }
955
956 void pt_add_gui_file(play_tree_t** ppt, char* path, char* file)
957 {
958   char* wholename = malloc(strlen(path)+strlen(file)+2);
959
960   if (wholename)
961   {
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!
967   }
968 }
969
970 void pt_iter_goto_head(play_tree_iter_t* iter)
971 {
972   iter->tree=iter->root;
973   play_tree_iter_step(iter, 0, 0);
974 }