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