Remove _GNU_SOURCE and string.h too
[vlc.git] / modules / visualization / galaktos / preset.c
1 /*****************************************************************************
2  * preset.c:
3  *****************************************************************************
4  * Copyright (C) 2004 the VideoLAN team
5  * $Id$
6  *
7  * Authors: Cyril Deguet <asmax@videolan.org>
8  *          code from projectM http://xmms-projectm.sourceforge.net
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23  *****************************************************************************/
24
25 #include <vlc/vlc.h>
26
27
28 #include <stdio.h>
29 #include <dirent.h>
30 #include <time.h>
31 #include "common.h"
32 #include "fatal.h"
33
34 #include "preset_types.h"
35 #include "preset.h"
36
37 #include "parser.h"
38
39 #include "expr_types.h"
40 #include "eval.h"
41
42 #include "splaytree_types.h"
43 #include "splaytree.h"
44 #include "tree_types.h"
45
46 #include "per_frame_eqn_types.h"
47 #include "per_frame_eqn.h"
48
49 #include "per_pixel_eqn_types.h"
50 #include "per_pixel_eqn.h"
51
52 #include "init_cond_types.h"
53 #include "init_cond.h"
54
55 #include "param_types.h"
56 #include "param.h"
57
58 #include "func_types.h"
59 #include "func.h"
60
61 #include "custom_wave_types.h"
62 #include "custom_wave.h"
63
64 #include "custom_shape_types.h"
65 #include "custom_shape.h"
66
67 #include "idle_preset.h"
68
69 /* The maximum number of preset names loaded into buffer */
70 #define MAX_PRESETS_IN_DIR 50000
71 extern int per_frame_eqn_count;
72 extern int per_frame_init_eqn_count;
73 //extern int custom_per_frame_eqn_count;
74
75 extern splaytree_t * builtin_param_tree;
76
77 preset_t * active_preset = NULL;
78 preset_t * idle_preset = NULL;
79 FILE * write_stream = NULL;
80
81
82 int preset_index = -1;
83 int preset_name_buffer_size = 0;
84 splaytree_t * chrono_order_preset_name_tree = NULL;
85 int get_preset_path(char ** preset_path_ptr, char * filepath, char * filename);
86 preset_t * load_preset(char * pathname);
87 int is_valid_extension(char * name);    
88 int load_preset_file(char * pathname, preset_t * preset);
89 int close_preset(preset_t * preset);
90
91 int write_preset_name(FILE * fs);
92 int write_per_pixel_equations(FILE * fs);
93 int write_per_frame_equations(FILE * fs);
94 int write_per_frame_init_equations(FILE * fs);
95 int write_init_conditions(FILE * fs);
96 void load_init_cond(param_t * param);
97 void load_init_conditions();
98 void write_init(init_cond_t * init_cond);
99 int init_idle_preset();
100 int destroy_idle_preset();
101 void load_custom_wave_init_conditions();
102 void load_custom_wave_init(custom_wave_t * custom_wave);
103
104 void load_custom_shape_init_conditions();
105 void load_custom_shape_init(custom_shape_t * custom_shape);
106
107 /* loadPresetDir: opens the directory buffer
108    denoted by 'dir' to load presets */
109    
110 int loadPresetDir(char * dir) {
111
112   struct dirent ** name_list;
113   char * preset_name;
114   int i, j, dir_size;
115   
116   if (dir == NULL)
117         return ERROR;
118  
119   if (chrono_order_preset_name_tree != NULL) {
120         if (PRESET_DEBUG) printf("loadPresetDir: previous directory doesn't appear to be closed!\n");
121         /* Let this slide for now */
122   }     
123   
124   /* Scan the entire directory, storing each entry in a dirent struct array that needs 
125      to be freed later. For more information, consult scandir(3) in the man pages */
126   if ((dir_size = scandir(dir, &name_list, 0, alphasort)) < 0) {
127         if (PRESET_DEBUG) printf("loadPresetDir: failed to open directory \"%s\"\n", dir);
128         return ERROR;
129   }
130   
131   chrono_order_preset_name_tree = create_splaytree(compare_int, copy_int, free_int);
132   
133   /* Iterate through entire dirent name list, adding to the preset name list if it
134      is valid */  
135   for (i = 0; ((i < dir_size) && (i < MAX_PRESETS_IN_DIR));i++) {
136
137         /* Only perform the next set of operations if the preset name 
138            contains a valid extension */
139         if (is_valid_extension(name_list[i]->d_name)) {
140                 
141                 /* Handle the out of memory case. My guess is xmms would
142                    crash before this program would, but whatever...*/
143                 if ((preset_name = (char*)malloc(MAX_PATH_SIZE)) == NULL) {
144                         if (PRESET_DEBUG) printf("loadPresetDir: out of memory! \n");
145                         
146                         /* Free the rest of the dirent name list */
147                         for (j = i; j < dir_size; j++) 
148                                 free(name_list[j]);
149                         destroy_splaytree(chrono_order_preset_name_tree);
150                         return OUTOFMEM_ERROR;
151                 }
152                                 
153                 /* Now create the full path */
154             if (get_preset_path(&preset_name, dir, name_list[i]->d_name) < 0) {
155                         if (PRESET_DEBUG) printf("loadPresetDir: failed to generate full preset path name!\n");
156                         
157                         /* Free the rest of the dirent name list */
158                         for (j = i; j < dir_size; j++) 
159                                 free(name_list[j]);
160                         destroy_splaytree(chrono_order_preset_name_tree);
161                         return OUTOFMEM_ERROR;
162                         
163                 }
164                 
165                 /* Insert the character string into the splay tree, with the key being its sequence number */
166                 splay_insert(preset_name, &preset_name_buffer_size, chrono_order_preset_name_tree);
167                 preset_name_buffer_size++;
168         }
169         
170         /* Free the dirent struct */
171         free(name_list[i]);
172         
173   }     
174   
175   free(name_list);
176   
177   /* No valid files in directory! */
178   if (chrono_order_preset_name_tree->root == NULL) {
179         if (PRESET_DEBUG) printf("loadPresetDir: no valid files in directory \"%s\"\n", dir);
180         destroy_splaytree(chrono_order_preset_name_tree);
181         chrono_order_preset_name_tree = NULL;
182         return FAILURE;   
183   }     
184           
185   /* Start the prefix index right before the first entry, so next preset
186      starts at the top of the list */
187   preset_index = -1;
188   
189   /* Start the first preset */
190
191   switchPreset(ALPHA_NEXT, HARD_CUT);
192   
193   return SUCCESS;
194 }
195
196 /* closePresetDir: closes the current
197    preset directory buffer */
198
199 int closePresetDir() {
200
201   /* No preset director appears to be loaded */ 
202   if (chrono_order_preset_name_tree == NULL) 
203     return SUCCESS;
204   
205   if (PRESET_DEBUG) {
206          printf("closePresetDir: freeing directory buffer...");
207          fflush(stdout);
208   }  
209   
210   /* Free each entry in the directory preset name tree */
211   splay_traverse(free_int, chrono_order_preset_name_tree);
212   
213   /* Destroy the chronological order splay tree */
214   destroy_splaytree(chrono_order_preset_name_tree);
215   chrono_order_preset_name_tree = NULL;
216   preset_name_buffer_size = 0;
217   if (PRESET_DEBUG) printf("finished\n");
218   
219   return SUCCESS;
220 }
221
222
223
224 /* Converts a preset file name to a full path */ 
225 int get_preset_path(char ** preset_path_ptr, char * filepath, char * filename) {
226
227   char * preset_path;
228         
229   /* An insanely paranoid sequence of argument checks */
230   if (preset_path_ptr == NULL)
231         return ERROR;
232   if (*preset_path_ptr == NULL)
233     return ERROR;
234   if (filename == NULL)
235         return ERROR;
236   if (filepath == NULL)
237         return ERROR;
238   
239   /* Mostly here for looks */
240   preset_path = *preset_path_ptr;
241
242   /* Clear the name space first */
243   memset(preset_path, 0, MAX_PATH_SIZE);
244   
245   /* Now create the string "PATH/FILENAME", where path is either absolute or relative location
246      of the .milk file, and filename is the name of the preset file itself */
247   strcat(
248         strcat(
249                 strncpy(
250                         preset_path, 
251                     filepath, 
252             MAX_PATH_SIZE-1),   
253         "/"), 
254     filename);  
255
256   return SUCCESS;
257 }       
258
259 /* switchPreset: loads the next preset from the directory stream.
260    loadPresetDir() must be called first. This is a
261    sequential load function */
262
263 int switchPreset(switch_mode_t switch_mode, int cut_type) {
264
265   preset_t * new_preset;
266         
267   int switch_index;
268         
269   /* Make sure a preset directory list is in the buffer */
270   if (chrono_order_preset_name_tree == NULL) {
271     if (PRESET_DEBUG) printf("switchPreset: it helps if you open a directory first with a loadPresetDir() call\n");
272     return ERROR;
273   }
274   
275   
276   switch (switch_mode) {
277           
278   case ALPHA_NEXT:
279   /* An index variable that iterates through the directory
280      buffer, doing wrap around when it reaches the end of
281          the buffer */
282   
283   if (preset_index == (preset_name_buffer_size - 1))
284                 switch_index = preset_index = 0;
285   else  
286                 switch_index = ++preset_index;
287   break;
288
289   case ALPHA_PREVIOUS:
290           
291   if (preset_index == 0)
292                 switch_index = preset_index = preset_name_buffer_size - 1;
293   else  
294                 switch_index = --preset_index;
295   break;
296   
297   case RANDOM_NEXT:
298         switch_index = (int) (preset_name_buffer_size*(rand()/(RAND_MAX+1.0)));
299         break;
300   case RESTART_ACTIVE:
301         switch_index = preset_index;
302         break;
303   default:
304         return FAILURE;
305   }
306   
307     
308   /* Finally, load the preset using its actual path */
309   if ((new_preset = load_preset((char*)splay_find(&switch_index, chrono_order_preset_name_tree))) == NULL) {
310         if (PRESET_DEBUG) printf("switchPreset: failed to load preset\n");
311         return ERROR;
312   }
313
314   /* Closes a preset currently loaded, if any */
315   if ((active_preset != NULL) && (active_preset != idle_preset))
316     close_preset(active_preset);
317
318   /* Sets global active_preset pointer */
319   active_preset = new_preset;
320
321  
322   /* Reinitialize the engine variables to sane defaults */
323   reset_engine_vars();
324
325   /* Add any missing initial conditions */
326   load_init_conditions();
327
328   /* Add any missing initial conditions for each wave */
329   load_custom_wave_init_conditions();
330
331 /* Add any missing initial conditions for each shape */
332   load_custom_shape_init_conditions();
333
334   /* Need to evaluate the initial conditions once */
335   evalInitConditions();
336
337  
338   //  evalInitPerFrameEquations();
339   return SUCCESS;
340 }
341
342 /* Loads a specific preset by absolute path */
343 int loadPresetByFile(char * filename) {
344
345   preset_t * new_preset;
346  
347   /* Finally, load the preset using its actual path */
348   if ((new_preset = load_preset(filename)) == NULL) {
349         if (PRESET_DEBUG) printf("loadPresetByFile: failed to load preset!\n");
350         return ERROR;     
351   }
352
353   /* Closes a preset currently loaded, if any */
354   if ((active_preset != NULL) && (active_preset != idle_preset))
355     close_preset(active_preset); 
356
357   /* Sets active preset global pointer */
358   active_preset = new_preset;
359
360   /* Reinitialize engine variables */
361   reset_engine_vars();
362
363  
364   /* Add any missing initial conditions for each wave */
365   load_custom_wave_init_conditions();
366
367  /* Add any missing initial conditions for each wave */
368   load_custom_shape_init_conditions();
369
370   /* Add any missing initial conditions */
371   load_init_conditions();
372   
373   /* Need to do this once for menu */
374   evalInitConditions();
375   //  evalPerFrameInitEquations();
376   return SUCCESS;
377
378 }
379
380 int init_idle_preset() {
381
382   preset_t * preset;
383   int i;
384
385     /* Initialize idle preset struct */
386   if ((preset = (preset_t*)malloc(sizeof(preset_t))) == NULL)
387     return FAILURE;
388
389   
390   strncpy(preset->name, "idlepreset", strlen("idlepreset"));
391
392   /* Initialize equation trees */
393   preset->init_cond_tree = create_splaytree(compare_string, copy_string, free_string);
394   preset->user_param_tree = create_splaytree(compare_string, copy_string, free_string);
395   preset->per_frame_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
396   preset->per_pixel_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
397   preset->per_frame_init_eqn_tree = create_splaytree(compare_string, copy_string, free_string);
398   preset->custom_wave_tree = create_splaytree(compare_int, copy_int, free_int);
399   preset->custom_shape_tree = create_splaytree(compare_int, copy_int, free_int);
400  
401   /* Set file path to dummy name */  
402   strncpy(preset->file_path, "IDLE PRESET", MAX_PATH_SIZE-1);
403   
404   /* Set initial index values */
405   preset->per_pixel_eqn_string_index = 0;
406   preset->per_frame_eqn_string_index = 0;
407   preset->per_frame_init_eqn_string_index = 0;
408   memset(preset->per_pixel_flag, 0, sizeof(int)*NUM_OPS);
409   
410   /* Clear string buffers */
411   memset(preset->per_pixel_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
412   memset(preset->per_frame_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
413   memset(preset->per_frame_init_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
414
415   idle_preset = preset;
416   
417   return SUCCESS;
418 }
419
420 int destroy_idle_preset() {
421
422   return close_preset(idle_preset);
423   
424 }
425
426 /* initPresetLoader: initializes the preset
427    loading library. this should be done before
428    any parsing */
429 int initPresetLoader() {
430
431   /* Initializes the builtin parameter database */
432   init_builtin_param_db();
433
434   /* Initializes the builtin function database */
435   init_builtin_func_db();
436         
437   /* Initializes all infix operators */
438   init_infix_ops();
439
440   /* Set the seed to the current time in seconds */
441   srand(time(NULL));
442
443   /* Initialize the 'idle' preset */
444   init_idle_preset();
445
446  
447
448   reset_engine_vars();
449
450   active_preset = idle_preset;
451   load_init_conditions();
452
453   /* Done */
454   if (PRESET_DEBUG) printf("initPresetLoader: finished\n");
455   return SUCCESS;
456 }
457
458 /* Sort of experimental code here. This switches
459    to a hard coded preset. Useful if preset directory
460    was not properly loaded, or a preset fails to parse */
461
462 void switchToIdlePreset() {
463
464
465   /* Idle Preset already activated */
466   if (active_preset == idle_preset)
467     return;
468
469
470   /* Close active preset */
471   if (active_preset != NULL)
472     close_preset(active_preset);
473
474   /* Sets global active_preset pointer */
475   active_preset = idle_preset;
476
477   /* Reinitialize the engine variables to sane defaults */
478   reset_engine_vars();
479
480   /* Add any missing initial conditions */
481   load_init_conditions();
482
483   /* Need to evaluate the initial conditions once */
484   evalInitConditions();
485
486 }
487
488 /* destroyPresetLoader: closes the preset
489    loading library. This should be done when 
490    projectM does cleanup */
491
492 int destroyPresetLoader() {
493   
494   if ((active_preset != NULL) && (active_preset != idle_preset)) {      
495         close_preset(active_preset);      
496   }     
497
498   active_preset = NULL;
499   
500   destroy_idle_preset();
501   destroy_builtin_param_db();
502   destroy_builtin_func_db();
503   destroy_infix_ops();
504
505   return SUCCESS;
506
507 }
508
509 /* load_preset_file: private function that loads a specific preset denoted
510    by the given pathname */
511 int load_preset_file(char * pathname, preset_t * preset) { 
512   FILE * fs;
513   int retval;
514
515   if (pathname == NULL)
516           return FAILURE;
517   if (preset == NULL)
518           return FAILURE;
519   
520   /* Open the file corresponding to pathname */
521   if ((fs = utf8_fopen(pathname, "r")) == 0) {
522     if (PRESET_DEBUG) printf("load_preset_file: loading of file %s failed!\n", pathname);
523     return ERROR;       
524   }
525
526   if (PRESET_DEBUG) printf("load_preset_file: file stream \"%s\" opened successfully\n", pathname);
527
528   /* Parse any comments */
529   if (parse_top_comment(fs) < 0) {
530     if (PRESET_DEBUG) printf("load_preset_file: no left bracket found...\n");
531     fclose(fs);
532     return FAILURE;
533   }
534   
535   /* Parse the preset name and a left bracket */
536   if (parse_preset_name(fs, preset->name) < 0) {
537     if (PRESET_DEBUG) printf("load_preset_file: loading of preset name in file \"%s\" failed\n", pathname);
538     fclose(fs);
539     return ERROR;
540   }
541   
542   if (PRESET_DEBUG) printf("load_preset_file: preset \"%s\" parsed\n", preset->name);
543
544   /* Parse each line until end of file */
545   if (PRESET_DEBUG) printf("load_preset_file: beginning line parsing...\n");
546   while ((retval = parse_line(fs, preset)) != EOF) {
547     if (retval == PARSE_ERROR) {
548       if (PRESET_DEBUG > 1) printf("load_preset_file: parse error in file \"%s\"\n", pathname);
549     }
550   }
551   
552   if (PRESET_DEBUG) printf("load_preset_file: finished line parsing successfully\n"); 
553
554   /* Now the preset has been loaded.
555      Evaluation calls can be made at appropiate
556      times in the frame loop */
557   
558   fclose(fs);
559    
560   if (PRESET_DEBUG) printf("load_preset_file: file \"%s\" closed, preset ready\n", pathname);
561   return SUCCESS;
562   
563 }
564
565 void evalInitConditions() {
566   splay_traverse(eval_init_cond, active_preset->init_cond_tree);
567   splay_traverse(eval_init_cond, active_preset->per_frame_init_eqn_tree);
568 }
569
570 void evalPerFrameEquations() {
571   splay_traverse(eval_per_frame_eqn, active_preset->per_frame_eqn_tree);
572 }
573
574 void evalPerFrameInitEquations() {
575   //printf("evalPerFrameInitEquations: per frame init unimplemented!\n");
576   //  splay_traverse(eval_per_frame_eqn, active_preset->per_frame_init_eqn_tree);
577 }       
578
579 /* Returns nonzero if string 'name' contains .milk or
580    (the better) .prjm extension. Not a very strong function currently */
581 int is_valid_extension(char * name) {
582
583         if (PRESET_DEBUG > 1) {
584                 printf("is_valid_extension: scanning string \"%s\"...", name);
585                 fflush(stdout);
586         }
587
588         if (strstr(name, MILKDROP_FILE_EXTENSION)) {
589                         if (PRESET_DEBUG > 1) printf("\".milk\" extension found in string [true]\n");
590                         return TRUE;
591         }       
592         
593         if (strstr(name, PROJECTM_FILE_EXTENSION)) {
594                     if (PRESET_DEBUG > 1) printf("\".prjm\" extension found in string [true]\n");
595                         return TRUE;
596         }
597          
598         if (PRESET_DEBUG > 1) printf("no valid extension found [false]\n");
599         return FALSE;
600 }
601
602 /* Private function to close a preset file */
603 int close_preset(preset_t * preset) {
604
605   if (preset == NULL)
606     return FAILURE;
607
608
609   splay_traverse(free_init_cond, preset->init_cond_tree);
610   destroy_splaytree(preset->init_cond_tree);
611   
612   splay_traverse(free_init_cond, preset->per_frame_init_eqn_tree);
613   destroy_splaytree(preset->per_frame_init_eqn_tree);
614   
615   splay_traverse(free_per_pixel_eqn, preset->per_pixel_eqn_tree);
616   destroy_splaytree(preset->per_pixel_eqn_tree);
617   
618   splay_traverse(free_per_frame_eqn, preset->per_frame_eqn_tree);
619   destroy_splaytree(preset->per_frame_eqn_tree);
620   
621   splay_traverse(free_param, preset->user_param_tree);
622   destroy_splaytree(preset->user_param_tree);
623   
624   splay_traverse(free_custom_wave, preset->custom_wave_tree);
625   destroy_splaytree(preset->custom_wave_tree);
626
627   splay_traverse(free_custom_shape, preset->custom_shape_tree);
628   destroy_splaytree(preset->custom_shape_tree);
629
630   free(preset); 
631   
632   return SUCCESS;
633
634 }
635
636 void reloadPerPixel(char *s, preset_t * preset) {
637   
638   FILE * fs;
639   int slen;
640   char c;
641   int i;
642
643   if (s == NULL)
644     return;
645
646   if (preset == NULL)
647     return;
648
649   /* Clear previous per pixel equations */
650   splay_traverse(free_per_pixel_eqn, preset->per_pixel_eqn_tree);
651   destroy_splaytree(preset->per_pixel_eqn_tree);
652   preset->per_pixel_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
653
654   /* Convert string to a stream */
655   fs = fmemopen (s, strlen(s), "r");
656
657   while ((c = fgetc(fs)) != EOF) {
658     ungetc(c, fs);
659     parse_per_pixel_eqn(fs, preset);
660   }
661
662   fclose(fs);
663
664   /* Clear string space */
665   memset(preset->per_pixel_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
666
667   /* Compute length of string */
668   slen = strlen(s);
669
670   /* Copy new string into buffer */
671   strncpy(preset->per_pixel_eqn_string_buffer, s, slen);
672
673   /* Yet again no bounds checking */
674   preset->per_pixel_eqn_string_index = slen;
675
676   /* Finished */
677  
678   return;
679 }
680
681 /* Obviously unwritten */
682 void reloadPerFrameInit(char *s, preset_t * preset) {
683
684 }
685
686 void reloadPerFrame(char * s, preset_t * preset) {
687
688   FILE * fs;
689   int slen;
690   char c;
691   int eqn_count = 1;
692   per_frame_eqn_t * per_frame;
693
694   if (s == NULL)
695     return;
696
697   if (preset == NULL)
698     return;
699
700   /* Clear previous per frame equations */
701   splay_traverse(free_per_frame_eqn, preset->per_frame_eqn_tree);
702   destroy_splaytree(preset->per_frame_eqn_tree);
703   preset->per_frame_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
704
705   /* Convert string to a stream */
706   fs = fmemopen (s, strlen(s), "r");
707
708   while ((c = fgetc(fs)) != EOF) {
709     ungetc(c, fs);
710     if ((per_frame = parse_per_frame_eqn(fs, eqn_count, preset)) != NULL) {
711       splay_insert(per_frame, &eqn_count, preset->per_frame_eqn_tree);
712       eqn_count++;
713     }
714   }
715
716   fclose(fs);
717
718   /* Clear string space */
719   memset(preset->per_frame_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
720
721   /* Compute length of string */
722   slen = strlen(s);
723
724   /* Copy new string into buffer */
725   strncpy(preset->per_frame_eqn_string_buffer, s, slen);
726
727   /* Yet again no bounds checking */
728   preset->per_frame_eqn_string_index = slen;
729
730   /* Finished */
731   printf("reloadPerFrame: %d eqns parsed succesfully\n", eqn_count-1);
732   return;
733
734 }
735
736 preset_t * load_preset(char * pathname) {
737
738   preset_t * preset;
739   int i;
740
741   /* Initialize preset struct */
742   if ((preset = (preset_t*)malloc(sizeof(preset_t))) == NULL)
743     return NULL;
744    
745   /* Initialize equation trees */
746   preset->init_cond_tree = create_splaytree(compare_string, copy_string, free_string);
747   preset->user_param_tree = create_splaytree(compare_string, copy_string, free_string);
748   preset->per_frame_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
749   preset->per_pixel_eqn_tree = create_splaytree(compare_int, copy_int, free_int);
750   preset->per_frame_init_eqn_tree = create_splaytree(compare_string, copy_string, free_string);
751   preset->custom_wave_tree = create_splaytree(compare_int, copy_int, free_int);
752   preset->custom_shape_tree = create_splaytree(compare_int, copy_int, free_int);
753
754   memset(preset->per_pixel_flag, 0, sizeof(int)*NUM_OPS);
755
756   /* Copy file path */  
757   strncpy(preset->file_path, pathname, MAX_PATH_SIZE-1);
758   
759   /* Set initial index values */
760   preset->per_pixel_eqn_string_index = 0;
761   preset->per_frame_eqn_string_index = 0;
762   preset->per_frame_init_eqn_string_index = 0;
763   
764   
765   /* Clear string buffers */
766   memset(preset->per_pixel_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
767   memset(preset->per_frame_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
768   memset(preset->per_frame_init_eqn_string_buffer, 0, STRING_BUFFER_SIZE);
769   
770   
771   if (load_preset_file(pathname, preset) < 0) {
772         if (PRESET_DEBUG) printf("load_preset: failed to load file \"%s\"\n", pathname);
773         close_preset(preset);
774         return NULL;
775   }
776
777   /* It's kind of ugly to reset these values here. Should definitely be placed in the parser somewhere */
778   per_frame_eqn_count = 0;
779   per_frame_init_eqn_count = 0;
780
781   /* Finished, return new preset */
782   return preset;
783 }
784
785 void savePreset(char * filename) {
786
787   FILE * fs;
788
789   if (filename == NULL)
790     return;
791   
792   /* Open the file corresponding to pathname */
793   if ((fs = utf8_fopen(filename, "w+")) == 0) {
794     if (PRESET_DEBUG) printf("savePreset: failed to create filename \"%s\"!\n", filename);
795     return;     
796   }
797
798   write_stream = fs;
799
800   if (write_preset_name(fs) < 0) {
801     write_stream = NULL;
802     fclose(fs);
803     return;
804   }
805
806   if (write_init_conditions(fs) < 0) {
807     write_stream = NULL;
808     fclose(fs);
809     return;
810   }
811
812   if (write_per_frame_init_equations(fs) < 0) {
813     write_stream = NULL;
814     fclose(fs);
815     return;
816   }
817
818   if (write_per_frame_equations(fs) < 0) {
819     write_stream = NULL;
820     fclose(fs);
821     return;
822   }
823
824   if (write_per_pixel_equations(fs) < 0) {
825     write_stream = NULL;
826     fclose(fs);
827     return;
828   }
829  
830   write_stream = NULL;
831   fclose(fs);
832
833 }
834
835 int write_preset_name(FILE * fs) {
836
837   char s[256];
838   int len;
839
840   memset(s, 0, 256);
841
842   if (fs == NULL)
843     return FAILURE;
844
845   /* Format the preset name in a string */
846   sprintf(s, "[%s]\n", active_preset->name);
847
848   len = strlen(s);
849
850   /* Write preset name to file stream */
851   if (fwrite(s, 1, len, fs) != len)
852     return FAILURE;
853
854   return SUCCESS;
855
856 }
857
858 int write_init_conditions(FILE * fs) {
859
860   if (fs == NULL)
861     return FAILURE;
862   if (active_preset == NULL)
863     return FAILURE;
864
865
866   splay_traverse(write_init, active_preset->init_cond_tree);
867   
868   return SUCCESS;
869 }
870
871 void write_init(init_cond_t * init_cond) {
872
873   char s[512];
874   int len;
875
876   if (write_stream == NULL)
877     return;
878
879   memset(s, 0, 512);
880
881   if (init_cond->param->type == P_TYPE_BOOL)
882     sprintf(s, "%s=%d\n", init_cond->param->name, init_cond->init_val.bool_val);
883
884   else if (init_cond->param->type == P_TYPE_INT)    
885     sprintf(s, "%s=%d\n", init_cond->param->name, init_cond->init_val.int_val);
886
887   else if (init_cond->param->type == P_TYPE_DOUBLE)
888   {
889     lldiv_t div = lldiv( init_cond->init_val.double_val * 1000000,1000000 );
890     sprintf(s, "%s="I64Fd".%06u\n", init_cond->param->name, div.quot,
891                     (unsigned int) div.rem );
892   }
893
894   else { printf("write_init: unknown parameter type!\n"); return; }
895
896   len = strlen(s);
897
898   if ((fwrite(s, 1, len, write_stream)) != len)
899     printf("write_init: failed writing to file stream! Out of disk space?\n");
900
901 }
902
903
904 int write_per_frame_init_equations(FILE * fs) {
905
906   int len;
907
908   if (fs == NULL)
909     return FAILURE;
910   if (active_preset == NULL)
911     return FAILURE;
912   
913   len = strlen(active_preset->per_frame_init_eqn_string_buffer);
914
915   if (fwrite(active_preset->per_frame_init_eqn_string_buffer, 1, len, fs) != len)
916     return FAILURE;
917
918   return SUCCESS;
919 }
920
921
922 int write_per_frame_equations(FILE * fs) {
923
924   int len;
925
926   if (fs == NULL)
927     return FAILURE;
928   if (active_preset == NULL)
929     return FAILURE;
930
931   len = strlen(active_preset->per_frame_eqn_string_buffer);
932
933   if (fwrite(active_preset->per_frame_eqn_string_buffer, 1, len, fs) != len)
934     return FAILURE;
935
936   return SUCCESS;
937 }
938
939
940 int write_per_pixel_equations(FILE * fs) {
941
942   int len;
943
944   if (fs == NULL)
945     return FAILURE;
946   if (active_preset == NULL)
947     return FAILURE;
948
949   len = strlen(active_preset->per_pixel_eqn_string_buffer);
950
951   if (fwrite(active_preset->per_pixel_eqn_string_buffer, 1, len, fs) != len)
952     return FAILURE;
953
954   return SUCCESS;
955 }
956
957
958 void load_init_conditions() {
959
960   splay_traverse(load_init_cond, builtin_param_tree);
961
962  
963 }
964
965 void load_init_cond(param_t * param) {
966
967   init_cond_t * init_cond;
968   value_t init_val;
969
970   /* Don't count read only parameters as initial conditions */
971   if (param->flags & P_FLAG_READONLY)
972     return;
973
974   /* If initial condition was not defined by the preset file, force a default one
975      with the following code */
976   if ((init_cond = splay_find(param->name, active_preset->init_cond_tree)) == NULL) {
977     
978     /* Make sure initial condition does not exist in the set of per frame initial equations */
979     if ((init_cond = splay_find(param->name, active_preset->per_frame_init_eqn_tree)) != NULL)
980       return;
981     
982     if (param->type == P_TYPE_BOOL)
983       init_val.bool_val = 0;
984     
985     else if (param->type == P_TYPE_INT)
986       init_val.int_val = *(int*)param->engine_val;
987
988     else if (param->type == P_TYPE_DOUBLE)
989       init_val.double_val = *(double*)param->engine_val;
990
991     //printf("%s\n", param->name);
992     /* Create new initial condition */
993     if ((init_cond = new_init_cond(param, init_val)) == NULL)
994       return;
995     
996     /* Insert the initial condition into this presets tree */
997     if (splay_insert(init_cond, init_cond->param->name, active_preset->init_cond_tree) < 0) {
998       free_init_cond(init_cond);
999       return;
1000     }
1001     
1002   }
1003  
1004 }
1005
1006 void load_custom_wave_init_conditions() {
1007
1008   splay_traverse(load_custom_wave_init, active_preset->custom_wave_tree);
1009
1010 }
1011
1012 void load_custom_wave_init(custom_wave_t * custom_wave) {
1013
1014   load_unspecified_init_conds(custom_wave);
1015
1016 }
1017
1018
1019 void load_custom_shape_init_conditions() {
1020
1021   splay_traverse(load_custom_shape_init, active_preset->custom_shape_tree);
1022
1023 }
1024
1025 void load_custom_shape_init(custom_shape_t * custom_shape) {
1026  
1027   load_unspecified_init_conds_shape(custom_shape);
1028  
1029 }