Update to MPlayer SVN rev 32628 and FFmpeg SVN rev 25754.
[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   //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   /* Roughly validate input data. Both, pt and child are going to be
222    * dereferenced, hence assure they're not NULL.
223    */
224   if (!pt || !child) {
225     mp_msg(MSGT_PLAYTREE, MSGL_ERR, "Internal error, attempt to add an empty child or use empty playlist\n");
226     return;
227   }
228
229 #ifdef MP_DEBUG
230   assert(pt->entry_type == PLAY_TREE_ENTRY_NODE);
231 #endif
232
233   //DEBUG_FF: Where are the children freed?
234   // Attention in using this function!
235   for(iter = pt->child ; iter != NULL ; iter = iter->next)
236     iter->parent = NULL;
237
238   // Go back to first one
239   for(iter = child ; iter->prev != NULL ; iter = iter->prev)
240     /* NOTHING */;
241
242   pt->child = iter;
243
244   for( ; iter != NULL ; iter= iter->next)
245     iter->parent = pt;
246
247 }
248
249 void
250 play_tree_set_parent(play_tree_t* pt, play_tree_t* parent) {
251   play_tree_t* iter;
252
253 #ifdef MP_DEBUG
254   assert(pt != NULL);
255 #endif
256
257   if(pt->parent)
258     pt->parent->child = NULL;
259
260   for(iter = pt ; iter != NULL ; iter = iter->next)
261     iter->parent = parent;
262
263   if(pt->prev) {
264     for(iter = pt->prev ; iter->prev != NULL ; iter = iter->prev)
265       iter->parent = parent;
266     iter->parent = parent;
267     parent->child = iter;
268   } else
269     parent->child = pt;
270
271 }
272
273
274 void
275 play_tree_add_file(play_tree_t* pt,char* file) {
276   int n = 0;
277   char* e;
278
279 #ifdef MP_DEBUG
280   assert(pt != NULL);
281   assert(pt->child == NULL);
282   assert(file != NULL);
283 #endif
284
285   if(pt->entry_type != PLAY_TREE_ENTRY_NODE &&
286      pt->entry_type != PLAY_TREE_ENTRY_FILE)
287     return;
288
289   if(pt->files) {
290     for(n = 0 ; pt->files[n] != NULL ; n++)
291       /* NOTHING */;
292   }
293   pt->files = realloc(pt->files, (n + 2) * sizeof(char*));
294   if(pt->files ==NULL) {
295     mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",(n+2)*(int)sizeof(char*));
296     return;
297   }
298
299   e = pt->files[n] = strdup(file);
300   pt->files[n+1] = NULL;
301
302   pt->entry_type = PLAY_TREE_ENTRY_FILE;
303
304 }
305
306 int
307 play_tree_remove_file(play_tree_t* pt,char* file) {
308   int n,f = -1;
309
310 #ifdef MP_DEBUG
311   assert(pt != NULL);
312   assert(file != NULL);
313   assert(pt->entry_type != PLAY_TREE_ENTRY_NODE);
314 #endif
315
316   for(n=0 ; pt->files[n] != NULL ; n++) {
317     if(strcmp(file,pt->files[n]) == 0)
318       f = n;
319   }
320
321   if(f < 0) // Not found
322     return 0;
323
324 #ifdef MP_DEBUG
325   assert(n > f);
326 #endif
327
328   free(pt->files[f]);
329
330   if(n > 1) {
331     memmove(&pt->files[f],&pt->files[f+1],(n-f)*sizeof(char*));
332     pt->files = realloc(pt->files, n * sizeof(char*));
333     if(pt->files == NULL) {
334       mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",(n+2)*(int)sizeof(char*));
335       return -1;
336     }
337   } else {
338     free(pt->files);
339     pt->files = NULL;
340   }
341
342   return 1;
343 }
344
345 void
346 play_tree_set_param(play_tree_t* pt, char* name, char* val) {
347   int n = 0;
348
349 #ifdef MP_DEBUG
350   assert(pt != NULL);
351   assert(name != NULL);
352 #endif
353
354   if(pt->params)
355     for ( ; pt->params[n].name != NULL ; n++ ) { }
356
357   pt->params = realloc(pt->params, (n + 2) * sizeof(play_tree_param_t));
358   if(pt->params == NULL) {
359       mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't realloc params (%d bytes of memory)\n",(n+2)*(int)sizeof(play_tree_param_t));
360       return;
361   }
362   pt->params[n].name = strdup(name);
363   pt->params[n].value = val != NULL ? strdup(val) : NULL;
364   memset(&pt->params[n+1],0,sizeof(play_tree_param_t));
365
366   return;
367 }
368
369 int
370 play_tree_unset_param(play_tree_t* pt, char* name) {
371   int n,ni = -1;
372
373 #ifdef MP_DEBUG
374   assert(pt != NULL);
375   assert(name != NULL);
376   assert(pt->params != NULL);
377 #endif
378
379   for(n = 0 ; pt->params[n].name != NULL ; n++) {
380     if(strcasecmp(pt->params[n].name,name) == 0)
381       ni = n;
382   }
383
384   if(ni < 0)
385     return 0;
386
387   free(pt->params[ni].name);
388   free(pt->params[ni].value);
389
390   if(n > 1) {
391     memmove(&pt->params[ni],&pt->params[ni+1],(n-ni)*sizeof(play_tree_param_t));
392     pt->params = realloc(pt->params, n * sizeof(play_tree_param_t));
393     if(pt->params == NULL) {
394       mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",n*(int)sizeof(play_tree_param_t));
395       return -1;
396     }
397   } else {
398     free(pt->params);
399     pt->params = NULL;
400   }
401
402   return 1;
403 }
404
405 void
406 play_tree_set_params_from(play_tree_t* dest,play_tree_t* src) {
407   int i;
408
409 #ifdef MP_DEBUG
410   assert(dest != NULL);
411   assert(src != NULL);
412 #endif
413
414   if(!src->params)
415     return;
416
417   for(i = 0; src->params[i].name != NULL ; i++)
418     play_tree_set_param(dest,src->params[i].name,src->params[i].value);
419   if(src->flags & PLAY_TREE_RND) // pass the random flag too
420     dest->flags |= PLAY_TREE_RND;
421
422 }
423
424 static void
425 play_tree_unset_flag(play_tree_t* pt, int flags , int deep) {
426   play_tree_t*  i;
427
428   pt->flags &= ~flags;
429
430   if(deep && pt->child) {
431     if(deep > 0) deep--;
432     for(i = pt->child ; i ; i = i->next)
433       play_tree_unset_flag(i,flags,deep);
434   }
435 }
436
437
438 //////////////////////////////////// ITERATOR //////////////////////////////////////
439
440 static void
441 play_tree_iter_push_params(play_tree_iter_t* iter) {
442   int n;
443   play_tree_t* pt;
444 #ifdef MP_DEBUG
445   assert(iter != NULL);
446   assert(iter->config != NULL);
447   assert(iter->tree != NULL);
448 #endif
449
450   pt = iter->tree;
451
452   // We always push a config because we can set some option
453   // while playing
454   m_config_push(iter->config);
455
456   if(pt->params == NULL)
457     return;
458
459
460   for(n = 0; pt->params[n].name != NULL ; n++) {
461     int e;
462     if((e = m_config_set_option(iter->config,pt->params[n].name,pt->params[n].value)) < 0) {
463       mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Error %d while setting option '%s' with value '%s'\n",e,
464              pt->params[n].name,pt->params[n].value);
465     }
466   }
467
468   if(!pt->child)
469     iter->entry_pushed = 1;
470   return;
471 }
472
473 play_tree_iter_t*
474 play_tree_iter_new(play_tree_t* pt,m_config_t* config) {
475   play_tree_iter_t* iter;
476
477 #ifdef MP_DEBUG
478   assert(pt != NULL);
479   assert(config != NULL);
480 #endif
481
482   if( ! play_tree_is_valid(pt))
483     return NULL;
484
485   iter = calloc(1,sizeof(play_tree_iter_t));
486   if(! iter) {
487       mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate new iterator (%d bytes of memory)\n",(int)sizeof(play_tree_iter_t));
488       return NULL;
489   }
490   iter->root = pt;
491   iter->tree = NULL;
492   iter->config = config;
493
494   if(pt->parent)
495     iter->loop = pt->parent->loop;
496
497   return iter;
498 }
499
500 void
501 play_tree_iter_free(play_tree_iter_t* iter) {
502
503 #ifdef MP_DEBUG
504   assert(iter != NULL);
505 #endif
506
507   if(iter->status_stack) {
508 #ifdef MP_DEBUG
509     assert(iter->stack_size > 0);
510 #endif
511     free(iter->status_stack);
512   }
513
514   free(iter);
515 }
516
517 static play_tree_t*
518 play_tree_rnd_step(play_tree_t* pt) {
519   int count = 0;
520   int r;
521   play_tree_t *i,*head;
522
523   // Count how many free choice we have
524   for(i = pt ; i->prev ; i = i->prev)
525     if(!(i->flags & PLAY_TREE_RND_PLAYED)) count++;
526   head = i;
527   if(!(i->flags & PLAY_TREE_RND_PLAYED)) count++;
528   for(i = pt->next ; i ; i = i->next)
529     if(!(i->flags & PLAY_TREE_RND_PLAYED)) count++;
530
531   if(!count) return NULL;
532
533   r = (int)((float)(count) * rand() / (RAND_MAX + 1.0));
534
535   for(i = head ; i  ; i=i->next) {
536     if(!(i->flags & PLAY_TREE_RND_PLAYED)) r--;
537     if(r < 0) return i;
538   }
539
540   mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Random stepping error\n");
541   return NULL;
542 }
543
544
545 int
546 play_tree_iter_step(play_tree_iter_t* iter, int d,int with_nodes) {
547   play_tree_t* pt;
548
549   if ( !iter ) return PLAY_TREE_ITER_ENTRY;
550   if ( !iter->root ) return PLAY_TREE_ITER_ENTRY;
551
552 #ifdef MP_DEBUG
553   assert(iter != NULL);
554   assert(iter->root != NULL);
555   //printf("PT : Stepping = %d\n",d);
556 #endif
557
558   if(iter->tree == NULL) {
559     iter->tree = iter->root;
560     return play_tree_iter_step(iter,0,with_nodes);
561   }
562
563   if(iter->config && iter->entry_pushed > 0) {
564     iter->entry_pushed = 0;
565     m_config_pop(iter->config);
566   }
567
568   if(iter->tree->parent && (iter->tree->parent->flags & PLAY_TREE_RND))
569     iter->mode = PLAY_TREE_ITER_RND;
570   else
571     iter->mode = PLAY_TREE_ITER_NORMAL;
572
573   iter->file = -1;
574   if(iter->mode == PLAY_TREE_ITER_RND)
575     pt = play_tree_rnd_step(iter->tree);
576   else if( d > 0 ) {
577     int i;
578     pt = iter->tree;
579     for(i = d ; i > 0 && pt ; i--)
580       pt = pt->next;
581     d = i ? i : 1;
582   } else if(d < 0) {
583     int i;
584     pt = iter->tree;
585     for(i = d ; i < 0 && pt ; i++)
586       pt = pt->prev;
587     d = i ? i : -1;
588   } else
589     pt = iter->tree;
590
591   if(pt == NULL) { // No next
592     // Must we loop?
593     if (iter->mode == PLAY_TREE_ITER_RND) {
594       if (iter->root->loop == 0)
595         return PLAY_TREE_ITER_END;
596       play_tree_unset_flag(iter->root, PLAY_TREE_RND_PLAYED, -1);
597       if (iter->root->loop > 0) iter->root->loop--;
598       // try again
599       return play_tree_iter_step(iter, 0, with_nodes);
600     } else
601     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) ) ) ) {
602       if(d > 0) { // Go back to the first one
603         for(pt = iter->tree ; pt->prev != NULL; pt = pt->prev)
604           /* NOTHNG */;
605         if(iter->loop > 0) iter->loop--;
606       } else if( d < 0 ) { // Or the last one
607         for(pt = iter->tree ; pt->next != NULL; pt = pt->next)
608           /* NOTHNG */;
609         if(iter->loop >= 0 && iter->loop < iter->tree->parent->loop) iter->loop++;
610       }
611       iter->tree = pt;
612       return play_tree_iter_step(iter,0,with_nodes);
613     }
614     // Go up one level
615     return play_tree_iter_up_step(iter,d,with_nodes);
616
617   }
618
619   // Is there any valid child?
620   if(pt->child && play_tree_is_valid(pt->child)) {
621     iter->tree = pt;
622     if(with_nodes) { // Stop on the node
623       return PLAY_TREE_ITER_NODE;
624     } else      // Or follow it
625       return play_tree_iter_down_step(iter,d,with_nodes);
626   }
627
628   // Is it a valid entry?
629   if(! play_tree_is_valid(pt)) {
630     if(d == 0) { // Can this happen ? FF: Yes!
631       mp_msg(MSGT_PLAYTREE,MSGL_ERR,"What to do now ???? Infinite loop if we continue\n");
632       return PLAY_TREE_ITER_ERROR;
633     } // Not a valid entry : go to next one
634     return play_tree_iter_step(iter,d,with_nodes);
635   }
636
637 #ifdef MP_DEBUG
638   assert(pt->files != NULL);
639 #endif
640
641   iter->tree = pt;
642
643   for(d = 0 ; iter->tree->files[d] != NULL ; d++)
644     /* NOTHING */;
645   iter->num_files = d;
646
647   if(iter->config) {
648     play_tree_iter_push_params(iter);
649     iter->entry_pushed = 1;
650     if(iter->mode == PLAY_TREE_ITER_RND)
651       pt->flags |= PLAY_TREE_RND_PLAYED;
652   }
653
654   return PLAY_TREE_ITER_ENTRY;
655
656 }
657
658 static int
659 play_tree_is_valid(play_tree_t* pt) {
660   play_tree_t* iter;
661
662 #ifdef MP_DEBUG
663   assert(pt != NULL);
664 #endif
665
666   if(pt->entry_type != PLAY_TREE_ENTRY_NODE) {
667 #ifdef MP_DEBUG
668     assert(pt->child == NULL);
669 #endif
670     return 1;
671   }
672   else if (pt->child != NULL) {
673     for(iter = pt->child ; iter != NULL ; iter = iter->next) {
674       if(play_tree_is_valid(iter))
675         return 1;
676     }
677   }
678   return 0;
679 }
680
681 int
682 play_tree_iter_up_step(play_tree_iter_t* iter, int d,int with_nodes) {
683
684 #ifdef MP_DEBUG
685   assert(iter != NULL);
686   assert(iter->tree != NULL);
687   //printf("PT : Go UP\n");
688 #endif
689
690   iter->file = -1;
691   if(iter->tree->parent == iter->root->parent)
692     return PLAY_TREE_ITER_END;
693
694 #ifdef MP_DEBUG
695   assert(iter->tree->parent != NULL);
696   assert(iter->stack_size > 0);
697   assert(iter->status_stack != NULL);
698 #endif
699
700   iter->stack_size--;
701   iter->loop = iter->status_stack[iter->stack_size];
702   if(iter->stack_size > 0)
703     iter->status_stack = realloc(iter->status_stack, iter->stack_size * sizeof(int));
704   else {
705     free(iter->status_stack);
706     iter->status_stack = NULL;
707   }
708   if(iter->stack_size > 0 && iter->status_stack == NULL) {
709     mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",iter->stack_size*(int)sizeof(char*));
710     return PLAY_TREE_ITER_ERROR;
711   }
712   iter->tree = iter->tree->parent;
713
714   // Pop subtree params
715   if(iter->config) {
716     m_config_pop(iter->config);
717     if(iter->mode == PLAY_TREE_ITER_RND)
718       iter->tree->flags |= PLAY_TREE_RND_PLAYED;
719   }
720
721   return play_tree_iter_step(iter,d,with_nodes);
722 }
723
724 int
725 play_tree_iter_down_step(play_tree_iter_t* iter, int d,int with_nodes) {
726
727 #ifdef MP_DEBUG
728   assert(iter->tree->files == NULL);
729   assert(iter->tree->child != NULL);
730   assert(iter->tree->child->parent == iter->tree);
731   //printf("PT : Go DOWN\n");
732 #endif
733
734   iter->file = -1;
735
736   //  Push subtree params
737   if(iter->config)
738     play_tree_iter_push_params(iter);
739
740   iter->stack_size++;
741   iter->status_stack = realloc(iter->status_stack, iter->stack_size * sizeof(int));
742   if(iter->status_stack == NULL) {
743     mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",iter->stack_size*(int)sizeof(int));
744     return PLAY_TREE_ITER_ERROR;
745   }
746   iter->status_stack[iter->stack_size-1] = iter->loop;
747   // Set new status
748   iter->loop = iter->tree->loop-1;
749   if(d >= 0)
750     iter->tree = iter->tree->child;
751   else {
752     play_tree_t* pt;
753     for(pt = iter->tree->child ; pt->next != NULL ; pt = pt->next)
754       /*NOTING*/;
755     iter->tree = pt;
756   }
757
758   return play_tree_iter_step(iter,0,with_nodes);
759 }
760
761 char*
762 play_tree_iter_get_file(play_tree_iter_t* iter, int d) {
763 #ifdef MP_DEBUG
764   assert(iter != NULL);
765   assert(iter->tree->child == NULL);
766 #endif
767
768   if(iter->tree->files == NULL)
769     return NULL;
770
771 #ifdef MP_DEBUG
772   assert(iter->num_files > 0);
773 #endif
774
775   if(iter->file >= iter->num_files-1 || iter->file < -1)
776     return NULL;
777
778   if(d > 0) {
779     if(iter->file >= iter->num_files - 1)
780       iter->file = 0;
781     else
782       iter->file++;
783   } else if(d < 0) {
784     if(iter->file <= 0)
785       iter->file = iter->num_files - 1;
786     else
787       iter->file--;
788   }
789   return iter->tree->files[iter->file];
790 }
791
792 play_tree_t*
793 play_tree_cleanup(play_tree_t* pt) {
794   play_tree_t* iter, *tmp, *first;
795
796 #ifdef MP_DEBUG
797   assert(pt != NULL);
798 #endif
799
800   if( ! play_tree_is_valid(pt)) {
801     play_tree_remove(pt,1,1);
802     return NULL;
803   }
804
805   first = pt->child;
806
807   for(iter = pt->child ; iter != NULL ; ) {
808     tmp = iter;
809     iter = iter->next;
810     if(! play_tree_is_valid(tmp)) {
811       play_tree_remove(tmp,1,1);
812       if(tmp == first) first = iter;
813     }
814   }
815
816   for(iter = first ; iter != NULL ; ) {
817     tmp = iter;
818     iter = iter->next;
819     play_tree_cleanup(tmp);
820   }
821
822   return pt;
823
824 }
825
826 play_tree_iter_t*
827 play_tree_iter_new_copy(play_tree_iter_t* old) {
828   play_tree_iter_t* iter;
829
830 #ifdef MP_DEBUG
831   assert(old != NULL);
832 #endif
833
834   iter = malloc(sizeof(play_tree_iter_t));
835   if(iter == NULL) {
836     mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",(int)sizeof(play_tree_iter_t));
837     return NULL;
838   }
839 ;
840   memcpy(iter,old,sizeof(play_tree_iter_t));
841   if(old->status_stack) {
842     iter->status_stack = malloc(old->stack_size * sizeof(int));
843     if(iter->status_stack == NULL) {
844       mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",old->stack_size * (int)sizeof(int));
845       free(iter);
846       return NULL;
847     }
848     memcpy(iter->status_stack,old->status_stack,iter->stack_size*sizeof(int));
849   }
850   iter->config = NULL;
851
852   return iter;
853 }
854
855 // HIGH Level API, by Fabian Franz (mplayer@fabian-franz.de)
856 //
857 play_tree_iter_t* pt_iter_create(play_tree_t** ppt, m_config_t* config)
858 {
859   play_tree_iter_t* r=NULL;
860 #ifdef MP_DEBUG
861   assert(*ppt!=NULL);
862 #endif
863
864   *ppt=play_tree_cleanup(*ppt);
865
866   if(*ppt) {
867     r = play_tree_iter_new(*ppt,config);
868     if (r && play_tree_iter_step(r,0,0) != PLAY_TREE_ITER_ENTRY)
869     {
870       play_tree_iter_free(r);
871       r = NULL;
872     }
873   }
874
875   return r;
876 }
877
878 void pt_iter_destroy(play_tree_iter_t** iter)
879 {
880   if (iter && *iter)
881   {
882     free(*iter);
883     iter=NULL;
884   }
885 }
886
887 char* pt_iter_get_file(play_tree_iter_t* iter, int d)
888 {
889   int i=0;
890   char* r;
891
892   if (iter==NULL)
893     return NULL;
894
895   r = play_tree_iter_get_file(iter,d);
896
897   while (!r && d!=0)
898   {
899     if (play_tree_iter_step(iter,d,0) != PLAY_TREE_ITER_ENTRY)
900         break;
901     r=play_tree_iter_get_file(iter,d);
902     i++;
903   }
904
905   return r;
906 }
907
908 void pt_iter_insert_entry(play_tree_iter_t* iter, play_tree_t* entry)
909 {
910   play_tree_t *pt = iter->tree;
911 #ifdef MP_DEBUG
912   assert(pt!=NULL);
913   assert(entry!=NULL);
914   assert(entry!=pt);
915 #endif
916
917   play_tree_insert_entry(pt, entry);
918   play_tree_set_params_from(entry,pt);
919 }
920
921 void pt_iter_replace_entry(play_tree_iter_t* iter, play_tree_t* entry)
922 {
923   play_tree_t *pt = iter->tree;
924
925   pt_iter_insert_entry(iter, entry);
926   play_tree_remove(pt, 1, 1);
927   iter->tree=entry;
928 }
929
930 //Add a new file as a new entry
931 void pt_add_file(play_tree_t** ppt, char* filename)
932 {
933   play_tree_t *pt = *ppt, *entry = play_tree_new();
934 #ifdef MP_DEBUG
935   assert(entry!=NULL);
936 #endif
937
938   play_tree_add_file(entry, filename);
939   if (pt)
940     play_tree_append_entry(pt, entry);
941   else
942   {
943     pt=entry;
944     *ppt=pt;
945   }
946   play_tree_set_params_from(entry,pt);
947 }
948
949 void pt_iter_goto_head(play_tree_iter_t* iter)
950 {
951   iter->tree=iter->root;
952   play_tree_iter_step(iter, 0, 0);
953 }