Update to MPlayer SVN rev 29319 and FFmpeg SVN rev 18938.
[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,ni = -1;
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       if(strcasecmp(pt->params[n].name,name) == 0)
333         ni = n;
334     }
335   }
336
337   if(ni > 0) {
338     if(pt->params[n].value != NULL) free(pt->params[n].value);
339     pt->params[n].value = val != NULL ? strdup(val) : NULL;
340     return;
341   }
342
343   pt->params = (play_tree_param_t*)realloc(pt->params,(n+2)*sizeof(play_tree_param_t));
344   if(pt->params == NULL) {
345       mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't realloc params (%d bytes of memory)\n",(n+2)*(int)sizeof(play_tree_param_t));
346       return;
347   }
348   pt->params[n].name = strdup(name);
349   pt->params[n].value = val != NULL ? strdup(val) : NULL;
350   memset(&pt->params[n+1],0,sizeof(play_tree_param_t));
351
352   return;
353 }
354
355 int
356 play_tree_unset_param(play_tree_t* pt, char* name) {
357   int n,ni = -1;
358
359 #ifdef MP_DEBUG
360   assert(pt != NULL);
361   assert(name != NULL);
362   assert(pt->params != NULL);
363 #endif
364
365   for(n = 0 ; pt->params[n].name != NULL ; n++) {
366     if(strcasecmp(pt->params[n].name,name) == 0)
367       ni = n;
368   }
369
370   if(ni < 0)
371     return 0;
372
373   if(pt->params[ni].name) free(pt->params[ni].name);
374   if(pt->params[ni].value) free(pt->params[ni].value);
375
376   if(n > 1) {
377     memmove(&pt->params[ni],&pt->params[ni+1],(n-ni)*sizeof(play_tree_param_t));
378     pt->params = (play_tree_param_t*)realloc(pt->params,n*sizeof(play_tree_param_t));
379     if(pt->params == NULL) {
380       mp_msg(MSGT_PLAYTREE,MSGL_ERR,"Can't allocate %d bytes of memory\n",n*(int)sizeof(play_tree_param_t));
381       return -1;
382     }
383   } else {
384     free(pt->params);
385     pt->params = NULL;
386   }
387
388   return 1;
389 }
390
391 void
392 play_tree_set_params_from(play_tree_t* dest,play_tree_t* src) {
393   int i;
394
395 #ifdef MP_DEBUG
396   assert(dest != NULL);
397   assert(src != NULL);
398 #endif
399
400   if(!src->params)
401     return;
402
403   for(i = 0; src->params[i].name != NULL ; i++)
404     play_tree_set_param(dest,src->params[i].name,src->params[i].value);
405   if(src->flags & PLAY_TREE_RND) // pass the random flag too
406     dest->flags |= PLAY_TREE_RND;
407
408 }
409
410 // all children if deep < 0
411 void
412 play_tree_set_flag(play_tree_t* pt, int flags , int deep) {
413   play_tree_t*  i;
414
415   pt->flags |= flags;
416
417   if(deep && pt->child) {
418     if(deep > 0) deep--;
419     for(i = pt->child ; i ; i = i->next)
420       play_tree_set_flag(i,flags,deep);
421   }
422 }
423
424 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 = (int*)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 = (int*)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_add_gui_file(play_tree_t** ppt, char* path, char* file)
950 {
951   char* wholename = malloc(strlen(path)+strlen(file)+2);
952
953   if (wholename)
954   {
955     strcpy(wholename, path);
956     strcat(wholename, "/");
957     strcat(wholename, file);
958     pt_add_file(ppt, wholename);
959     free(wholename); // As pt_add_file strdups it anyway!
960   }
961 }
962
963 void pt_iter_goto_head(play_tree_iter_t* iter)
964 {
965   iter->tree=iter->root;
966   play_tree_iter_step(iter, 0, 0);
967 }