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 }