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