diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/paranormal/presets.c	Mon Oct 30 23:02:33 2006 -0800
@@ -0,0 +1,261 @@
+/* FIXME: add documentation support to preset files */
+/* FIXME: add multiple-presets-per-file support (maybe) */
+
+#ifdef HAVE_CONFIG_H
+# include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <libxml/parser.h>
+#include <libxml/xmlmemory.h>
+
+#include "paranormal.h"
+#include "actuators.h"
+#include "containers.h"
+
+/* cur->name should be the actuator name */
+static void
+parse_actuator (xmlNodePtr cur, struct pn_actuator *a)
+{
+  int i;
+  xmlChar *content;
+  struct pn_actuator *child;
+
+  for (cur = cur->xmlChildrenNode; cur; cur = cur->next)
+    {
+      if (xmlIsBlankNode (cur) || cur->type != XML_ELEMENT_NODE)
+	continue;
+
+      /* see if it's an option */
+      for (i=0; a->options && a->options[i].desc; i++)
+	if (! xmlStrcmp (cur->name,
+			 (const xmlChar *) a->options[i].desc->name))
+	  break;
+
+      if (a->options && a->options[i].desc)
+	{
+	  /* it is an option, so let's set it! */
+	  content = xmlNodeGetContent (cur);
+
+	  /* FIXME: warning? */
+	  if (! content)
+	    continue;
+
+	  /* FIXME: perhaps do a little better job of error checking? */
+	  switch (a->options[i].desc->type)
+	    {
+	    case OPT_TYPE_INT:
+	      a->options[i].val.ival = (int)strtol (content, NULL, 0);
+	      break;
+	    case OPT_TYPE_FLOAT:
+	      a->options[i].val.fval = (float)strtod (content, NULL);
+	      break;
+	    case OPT_TYPE_STRING:
+	      a->options[i].val.sval = g_strdup (content);
+	      break;
+	    case OPT_TYPE_COLOR:
+	      {
+		guint r,g,b;
+		char *s = content+1;
+		r = strtoul (s, &s, 0);
+		if (r > 255 || ! (s = strchr (s, ',')))
+		  goto bad_color;
+		g = strtoul (s+1, &s, 0);
+		if (g > 255 || ! (s = strchr (s, ',')))
+		  goto bad_color;
+		b = strtoul (s+1, NULL, 0);
+		if (b > 255)
+		  goto bad_color;
+
+		a->options[i].val.cval.r = (guchar)r;
+		a->options[i].val.cval.g = (guchar)g;
+		a->options[i].val.cval.b = (guchar)b;
+
+		break;
+	      }
+	    bad_color:
+	      pn_error ("parse error: invalid color value: option \"%s\" ignored.\n"
+			"  correct syntax: (r,g,b) where r, g, and b are the\n"
+			"  red, green, and blue components of the "
+			"color, respectively", cur->name);
+	      break;
+	      
+	    case OPT_TYPE_COLOR_INDEX:
+	      {
+		int c = (int)strtol (content, NULL, 0);
+		if (c < 0 || c > 255)
+		  pn_error ("parse error: invalid color index \"%s\" (%d): option ignored.\n"
+			    "  the value must be between 0 and 255",
+			    cur->name, c);
+		else
+		  a->options[i].val.ival = c;
+		break;
+	      }
+	    case OPT_TYPE_BOOLEAN:
+	      {
+		char *c, *d;
+		for (c=content; isspace (*c); c++);
+		for (d=c; !isspace(*d); d++);
+		*d = '\0';
+		if (g_strcasecmp (c, "true") == 0)
+		  a->options[i].val.bval = TRUE;
+		else if (g_strcasecmp (c, "false") == 0)
+		  a->options[i].val.bval = FALSE;
+		else
+		  pn_error ("parse error: invalid boolean value \"%s\" (%s): option ignored.\n"
+			    "  the value must be either 'true' or 'false'",
+			    cur->name, c);
+	      }
+	    }
+
+	  /* gotta free content */
+	  xmlFree (content);
+	}
+      /* See if we have a child actuator */
+      else if (a->desc->flags & ACTUATOR_FLAG_CONTAINER
+	       && (child = create_actuator (cur->name)))
+	{
+	  container_add_actuator (a, child);
+	  parse_actuator (cur, child);
+	}
+      else
+	/* We have an error */
+	pn_error ("parse error: unknown entity \"%s\": ignored.", cur->name);
+    }
+}
+
+struct pn_actuator *
+load_preset (const char *filename)
+{
+  xmlDocPtr doc;
+  xmlNodePtr cur;
+  struct pn_actuator *a = NULL;
+
+  doc = xmlParseFile (filename);
+  if (! doc)
+    return NULL;
+
+  cur = xmlDocGetRootElement (doc);
+  if (! cur)
+    xmlFreeDoc (doc);
+
+  if (xmlStrcmp (cur->name, (const xmlChar *) "paranormal_preset"))
+    {
+      xmlFreeDoc (doc);
+      return NULL;
+    }
+
+  for (cur = cur->children; cur; cur = cur->next)
+    {
+      if (xmlIsBlankNode (cur) || cur->type != XML_ELEMENT_NODE)
+	continue;
+
+      /* if (...) { ... } else if (is_documentation [see top of file]) ... else */
+      {
+	a = create_actuator (cur->name);
+
+	/* FIXME: warn? */
+	if (! a)
+	  continue;
+
+	parse_actuator (cur, a);
+	break;
+      }
+    }
+
+  /* Don't need this any longer */
+  xmlFreeDoc (doc);
+
+  return a;
+}
+
+/* FIXME: do the file writing w/ error checking */
+static gboolean
+save_preset_recursive (FILE *file, const struct pn_actuator *actuator,
+		       int recursion_depth)
+{
+  int i;
+  GSList *child;
+
+  /* open this actuator */
+  fprintf (file, "%*s<%s>\n", recursion_depth, "", actuator->desc->name);
+
+  /* options */
+  if (actuator->options)
+    for (i=0; actuator->options[i].desc; i++)
+      {
+	fprintf (file, "%*s <%s> ", recursion_depth, "",
+		 actuator->desc->option_descs[i].name);
+	switch (actuator->desc->option_descs[i].type)
+	  {
+	  case OPT_TYPE_INT:
+	  case OPT_TYPE_COLOR_INDEX:
+	    fprintf (file, "%d", actuator->options[i].val.ival);
+	    break;
+	  case OPT_TYPE_FLOAT:
+	    fprintf (file, "%.5f", actuator->options[i].val.fval);
+	    break;
+	  case OPT_TYPE_STRING:
+	    fprintf (file, "%s", actuator->options[i].val.sval);
+	    break;
+	  case OPT_TYPE_COLOR:
+	    fprintf (file, "%d, %d, %d", actuator->options[i].val.cval.r,
+		     actuator->options[i].val.cval.g,
+		     actuator->options[i].val.cval.b);
+	    break;
+	  case OPT_TYPE_BOOLEAN:
+	    if (actuator->options[i].val.bval)
+	      fprintf (file, "TRUE");
+	    else
+	      fprintf (file, "FALSE");
+	    break;
+	  }
+	fprintf (file, " </%s>\n", actuator->desc->option_descs[i].name);
+      }
+
+  /* children */
+  if (actuator->desc->flags & ACTUATOR_FLAG_CONTAINER)
+    for (child = *(GSList **)actuator->data; child; child = child->next)
+      if (! save_preset_recursive (file, (struct pn_actuator*) child->data,
+				   recursion_depth+1))
+	return FALSE;
+
+  /* close the actuator */
+  fprintf (file, "%*s</%s>\n", recursion_depth, "", actuator->desc->name);
+
+  return TRUE;
+}
+
+gboolean
+save_preset (const char *filename, const struct pn_actuator *actuator)
+{
+  FILE *file;
+
+  file = fopen (filename, "w");
+  if (! file)
+    {
+      pn_error ("fopen: %s", strerror (errno));
+      return FALSE;
+    }
+
+  fprintf (file, "<?xml version=\"1.0\"?>\n\n<paranormal_preset>\n");
+
+  if (actuator)
+    if (! save_preset_recursive (file, actuator, 1))
+      {
+	fclose (file);
+	return FALSE;
+      }
+
+  fprintf (file, "</paranormal_preset>");
+
+  fclose (file);
+
+  return TRUE;
+
+}