Mercurial > audlegacy-plugins
comparison src/paranormal/presets.c @ 149:fd9c0a5871ac trunk
[svn] - new and IMPROVED paranormal visualization studio
author | nenolod |
---|---|
date | Mon, 30 Oct 2006 23:02:33 -0800 |
parents | |
children | 9549fea94794 |
comparison
equal
deleted
inserted
replaced
148:9d9fc9e1de48 | 149:fd9c0a5871ac |
---|---|
1 /* FIXME: add documentation support to preset files */ | |
2 /* FIXME: add multiple-presets-per-file support (maybe) */ | |
3 | |
4 #ifdef HAVE_CONFIG_H | |
5 # include <config.h> | |
6 #endif | |
7 | |
8 #include <stdlib.h> | |
9 #include <ctype.h> | |
10 #include <string.h> | |
11 #include <errno.h> | |
12 | |
13 #include <glib.h> | |
14 #include <libxml/parser.h> | |
15 #include <libxml/xmlmemory.h> | |
16 | |
17 #include "paranormal.h" | |
18 #include "actuators.h" | |
19 #include "containers.h" | |
20 | |
21 /* cur->name should be the actuator name */ | |
22 static void | |
23 parse_actuator (xmlNodePtr cur, struct pn_actuator *a) | |
24 { | |
25 int i; | |
26 xmlChar *content; | |
27 struct pn_actuator *child; | |
28 | |
29 for (cur = cur->xmlChildrenNode; cur; cur = cur->next) | |
30 { | |
31 if (xmlIsBlankNode (cur) || cur->type != XML_ELEMENT_NODE) | |
32 continue; | |
33 | |
34 /* see if it's an option */ | |
35 for (i=0; a->options && a->options[i].desc; i++) | |
36 if (! xmlStrcmp (cur->name, | |
37 (const xmlChar *) a->options[i].desc->name)) | |
38 break; | |
39 | |
40 if (a->options && a->options[i].desc) | |
41 { | |
42 /* it is an option, so let's set it! */ | |
43 content = xmlNodeGetContent (cur); | |
44 | |
45 /* FIXME: warning? */ | |
46 if (! content) | |
47 continue; | |
48 | |
49 /* FIXME: perhaps do a little better job of error checking? */ | |
50 switch (a->options[i].desc->type) | |
51 { | |
52 case OPT_TYPE_INT: | |
53 a->options[i].val.ival = (int)strtol (content, NULL, 0); | |
54 break; | |
55 case OPT_TYPE_FLOAT: | |
56 a->options[i].val.fval = (float)strtod (content, NULL); | |
57 break; | |
58 case OPT_TYPE_STRING: | |
59 a->options[i].val.sval = g_strdup (content); | |
60 break; | |
61 case OPT_TYPE_COLOR: | |
62 { | |
63 guint r,g,b; | |
64 char *s = content+1; | |
65 r = strtoul (s, &s, 0); | |
66 if (r > 255 || ! (s = strchr (s, ','))) | |
67 goto bad_color; | |
68 g = strtoul (s+1, &s, 0); | |
69 if (g > 255 || ! (s = strchr (s, ','))) | |
70 goto bad_color; | |
71 b = strtoul (s+1, NULL, 0); | |
72 if (b > 255) | |
73 goto bad_color; | |
74 | |
75 a->options[i].val.cval.r = (guchar)r; | |
76 a->options[i].val.cval.g = (guchar)g; | |
77 a->options[i].val.cval.b = (guchar)b; | |
78 | |
79 break; | |
80 } | |
81 bad_color: | |
82 pn_error ("parse error: invalid color value: option \"%s\" ignored.\n" | |
83 " correct syntax: (r,g,b) where r, g, and b are the\n" | |
84 " red, green, and blue components of the " | |
85 "color, respectively", cur->name); | |
86 break; | |
87 | |
88 case OPT_TYPE_COLOR_INDEX: | |
89 { | |
90 int c = (int)strtol (content, NULL, 0); | |
91 if (c < 0 || c > 255) | |
92 pn_error ("parse error: invalid color index \"%s\" (%d): option ignored.\n" | |
93 " the value must be between 0 and 255", | |
94 cur->name, c); | |
95 else | |
96 a->options[i].val.ival = c; | |
97 break; | |
98 } | |
99 case OPT_TYPE_BOOLEAN: | |
100 { | |
101 char *c, *d; | |
102 for (c=content; isspace (*c); c++); | |
103 for (d=c; !isspace(*d); d++); | |
104 *d = '\0'; | |
105 if (g_strcasecmp (c, "true") == 0) | |
106 a->options[i].val.bval = TRUE; | |
107 else if (g_strcasecmp (c, "false") == 0) | |
108 a->options[i].val.bval = FALSE; | |
109 else | |
110 pn_error ("parse error: invalid boolean value \"%s\" (%s): option ignored.\n" | |
111 " the value must be either 'true' or 'false'", | |
112 cur->name, c); | |
113 } | |
114 } | |
115 | |
116 /* gotta free content */ | |
117 xmlFree (content); | |
118 } | |
119 /* See if we have a child actuator */ | |
120 else if (a->desc->flags & ACTUATOR_FLAG_CONTAINER | |
121 && (child = create_actuator (cur->name))) | |
122 { | |
123 container_add_actuator (a, child); | |
124 parse_actuator (cur, child); | |
125 } | |
126 else | |
127 /* We have an error */ | |
128 pn_error ("parse error: unknown entity \"%s\": ignored.", cur->name); | |
129 } | |
130 } | |
131 | |
132 struct pn_actuator * | |
133 load_preset (const char *filename) | |
134 { | |
135 xmlDocPtr doc; | |
136 xmlNodePtr cur; | |
137 struct pn_actuator *a = NULL; | |
138 | |
139 doc = xmlParseFile (filename); | |
140 if (! doc) | |
141 return NULL; | |
142 | |
143 cur = xmlDocGetRootElement (doc); | |
144 if (! cur) | |
145 xmlFreeDoc (doc); | |
146 | |
147 if (xmlStrcmp (cur->name, (const xmlChar *) "paranormal_preset")) | |
148 { | |
149 xmlFreeDoc (doc); | |
150 return NULL; | |
151 } | |
152 | |
153 for (cur = cur->children; cur; cur = cur->next) | |
154 { | |
155 if (xmlIsBlankNode (cur) || cur->type != XML_ELEMENT_NODE) | |
156 continue; | |
157 | |
158 /* if (...) { ... } else if (is_documentation [see top of file]) ... else */ | |
159 { | |
160 a = create_actuator (cur->name); | |
161 | |
162 /* FIXME: warn? */ | |
163 if (! a) | |
164 continue; | |
165 | |
166 parse_actuator (cur, a); | |
167 break; | |
168 } | |
169 } | |
170 | |
171 /* Don't need this any longer */ | |
172 xmlFreeDoc (doc); | |
173 | |
174 return a; | |
175 } | |
176 | |
177 /* FIXME: do the file writing w/ error checking */ | |
178 static gboolean | |
179 save_preset_recursive (FILE *file, const struct pn_actuator *actuator, | |
180 int recursion_depth) | |
181 { | |
182 int i; | |
183 GSList *child; | |
184 | |
185 /* open this actuator */ | |
186 fprintf (file, "%*s<%s>\n", recursion_depth, "", actuator->desc->name); | |
187 | |
188 /* options */ | |
189 if (actuator->options) | |
190 for (i=0; actuator->options[i].desc; i++) | |
191 { | |
192 fprintf (file, "%*s <%s> ", recursion_depth, "", | |
193 actuator->desc->option_descs[i].name); | |
194 switch (actuator->desc->option_descs[i].type) | |
195 { | |
196 case OPT_TYPE_INT: | |
197 case OPT_TYPE_COLOR_INDEX: | |
198 fprintf (file, "%d", actuator->options[i].val.ival); | |
199 break; | |
200 case OPT_TYPE_FLOAT: | |
201 fprintf (file, "%.5f", actuator->options[i].val.fval); | |
202 break; | |
203 case OPT_TYPE_STRING: | |
204 fprintf (file, "%s", actuator->options[i].val.sval); | |
205 break; | |
206 case OPT_TYPE_COLOR: | |
207 fprintf (file, "%d, %d, %d", actuator->options[i].val.cval.r, | |
208 actuator->options[i].val.cval.g, | |
209 actuator->options[i].val.cval.b); | |
210 break; | |
211 case OPT_TYPE_BOOLEAN: | |
212 if (actuator->options[i].val.bval) | |
213 fprintf (file, "TRUE"); | |
214 else | |
215 fprintf (file, "FALSE"); | |
216 break; | |
217 } | |
218 fprintf (file, " </%s>\n", actuator->desc->option_descs[i].name); | |
219 } | |
220 | |
221 /* children */ | |
222 if (actuator->desc->flags & ACTUATOR_FLAG_CONTAINER) | |
223 for (child = *(GSList **)actuator->data; child; child = child->next) | |
224 if (! save_preset_recursive (file, (struct pn_actuator*) child->data, | |
225 recursion_depth+1)) | |
226 return FALSE; | |
227 | |
228 /* close the actuator */ | |
229 fprintf (file, "%*s</%s>\n", recursion_depth, "", actuator->desc->name); | |
230 | |
231 return TRUE; | |
232 } | |
233 | |
234 gboolean | |
235 save_preset (const char *filename, const struct pn_actuator *actuator) | |
236 { | |
237 FILE *file; | |
238 | |
239 file = fopen (filename, "w"); | |
240 if (! file) | |
241 { | |
242 pn_error ("fopen: %s", strerror (errno)); | |
243 return FALSE; | |
244 } | |
245 | |
246 fprintf (file, "<?xml version=\"1.0\"?>\n\n<paranormal_preset>\n"); | |
247 | |
248 if (actuator) | |
249 if (! save_preset_recursive (file, actuator, 1)) | |
250 { | |
251 fclose (file); | |
252 return FALSE; | |
253 } | |
254 | |
255 fprintf (file, "</paranormal_preset>"); | |
256 | |
257 fclose (file); | |
258 | |
259 return TRUE; | |
260 | |
261 } |