brewco/rdrecipes.c

changeset 459
1f88be70f253
child 460
0b2ea0ec165c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/brewco/rdrecipes.c	Tue Dec 15 23:11:42 2015 +0100
@@ -0,0 +1,655 @@
+/*****************************************************************************
+ * Copyright (C) 2015
+ *   
+ * Michiel Broek <mbroek at mbse dot eu>
+ *
+ * This file is part of the mbsePi-apps
+ *
+ * This is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * mbsePi-apps is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with ThermFerm; see the file COPYING.  If not, write to the Free
+ * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
+ *****************************************************************************/
+
+#include "brewco.h"
+#include "rdrecipes.h"
+#include "util.h"
+#include "xutil.h"
+
+extern int	debug;
+
+a_recipe	*recipes = NULL;
+
+
+const char	SKIPYN[2][4] = { "NO", "YES" };
+
+
+#define MY_ENCODING "utf-8"
+
+
+int do_wrrecipes(void);
+int do_wrrecipes(void)
+{
+    int			i, rc = 0;
+    FILE		*fp;
+    char		*mypath = NULL;
+    a_recipe		*recipe;
+    xmlTextWriterPtr	writer;
+    xmlBufferPtr	buf;
+
+    /* 
+     * Create a new XML buffer, to which the XML document will be written
+     */
+    if ((buf = xmlBufferCreate()) == NULL) {
+	syslog(LOG_NOTICE, "wrrecipes: error creating the xml buffer");
+	return 1;
+    }
+
+    /* 
+     * Create a new XmlWriter for memory, with no compression.
+     */
+    if ((writer = xmlNewTextWriterMemory(buf, 0)) == NULL) {
+	syslog(LOG_NOTICE, "wrrecipes: error creating the xml writer");
+	return 1;
+    }
+
+    /*
+     * Use indentation instead of one long line
+     */
+    if ((rc = xmlTextWriterSetIndent(writer, 2)) < 0) {
+	syslog(LOG_NOTICE, "wrrecipes: error setting Indent");
+	return 1;
+    }
+
+    /* 
+     * Start the document with the xml default for the version,
+     * encoding ISO 8859-1 and the default for the standalone
+     * declaration. 
+     */
+    if ((rc = xmlTextWriterStartDocument(writer, NULL, MY_ENCODING, NULL)) < 0) {
+	syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterStartDocument");
+	return 1;
+    }
+
+    /* 
+     * Start an element named "BREWCO". Since thist is the first
+     * element, this will be the root element of the document.
+     */
+    if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "BREWCO")) < 0) {
+	syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterStartElement");
+	return 1;
+    }
+
+    if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "RECIPES")) < 0) {
+	syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterStartElement");
+	return 1;
+    }
+
+    for (recipe = recipes; recipe; recipe = recipe->next) {
+
+	if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "RECIPE")) < 0) {
+	    syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterStartElement");
+	    return 1;
+	}
+
+	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "UUID", "%s", recipe->uuid)) < 0) {
+	    syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+	    return 1;
+	}
+	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "CODE", "%s", recipe->code)) < 0) {
+	    syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+	    return 1;
+	}
+	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", recipe->name)) < 0) {
+	    syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+	    return 1;
+	}
+	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "BOILTIME", "%d", recipe->boiltime)) < 0) {
+	    syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+	    return 1;
+	}
+	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "STARTTIME", "%d", (int)recipe->starttime)) < 0) {
+	    syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+	    return 1;
+	}
+	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "ENDTIME", "%d", (int)recipe->endtime)) < 0) {
+	    syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+	    return 1;
+	}
+
+	/*
+	 * 8 Mash steps
+	 */
+	if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "MASHSTEPS")) < 0) {
+	    syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterStartElement");
+	    return 1;
+	}
+	for (i =0; i < 8; i++) {
+	    if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "MASHSTEP")) < 0) {
+		syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterStartElement");
+		return 1;
+	    }
+	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", recipe->mash[i].name)) < 0) {
+		syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+		return 1;
+	    }
+	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MIN", "%d", recipe->mash[i].min)) < 0) {
+		syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+		return 1;
+	    }
+	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MAX", "%d", recipe->mash[i].max)) < 0) {
+		syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+		return 1;
+	    }
+	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "CANSKIP", "%s", recipe->mash[i].canskip ? "YES":"NO")) < 0) {
+		syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+		return 1;
+	    }
+	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "SETPOINT", "%f", recipe->mash[i].setpoint)) < 0) {
+		syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+		return 1;
+	    }
+	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "SKIP", "%s", recipe->mash[i].skip ? "YES":"NO")) < 0) {
+		syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+		return 1;
+	    }
+	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "DURATION", "%d", recipe->mash[i].duration)) < 0) {
+		syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+		return 1;
+	    }
+	    if ((rc = xmlTextWriterEndElement(writer)) < 0) {
+		syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterEndElement");
+		return 1;
+	    }
+	}
+	if ((rc = xmlTextWriterEndElement(writer)) < 0) {
+	    syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterEndElement");
+	    return 1;
+	}
+
+	/*
+	 * 10 Hop additions
+	 */
+	if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "HOPADDITIONS")) < 0) {
+	    syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterStartElement");
+	    return 1;
+	}
+	for (i = 0; i < 10; i++) {
+	    if (recipe->hops[i].name) {
+	        if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "HOPADDITION")) < 0) {
+		    syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterStartElement");
+		    return 1;
+	    	}
+	    	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", recipe->hops[i].name)) < 0) {
+		    syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+		    return 1;
+	    	}
+	    	if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "BOILTIME", "%d", recipe->hops[i].boiltime)) < 0) {
+		    syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+		    return 1;
+	    	}
+	    	if ((rc = xmlTextWriterEndElement(writer)) < 0) {
+		    syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterEndElement");
+		    return 1;
+	    	}
+	    }
+	}
+	if ((rc = xmlTextWriterEndElement(writer)) < 0) {
+	    syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterEndElement");
+	    return 1;
+	}
+
+	/*
+	 * 3 Hop stands
+	 */
+	if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "HOPSTANDS")) < 0) {
+	    syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterStartElement");
+	    return 1;
+	}                                       
+	for (i = 0; i < 3; i++) {
+	    if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "HOPSTAND")) < 0) {
+		syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterStartElement");
+		return 1;
+	    }
+	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", recipe->hopstand[i].name)) < 0) {
+		syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+		return 1;
+	    }
+	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MIN", "%d", recipe->hopstand[i].min)) < 0) {
+		syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+		return 1;
+	    }
+	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MAX", "%d", recipe->hopstand[i].max)) < 0) {
+		syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+		return 1;
+	    }
+	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HOLD", "%s", recipe->hopstand[i].hold ? "YES":"NO")) < 0) {
+		syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+		return 1;
+	    }
+	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "SETPOINT", "%f", recipe->hopstand[i].setpoint)) < 0) {
+		syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+		return 1;
+	    }
+	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "SKIP", "%s", recipe->hopstand[i].skip ? "YES":"NO")) < 0) {
+		syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+		return 1;
+	    }
+	    if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "DURATION", "%d", recipe->hopstand[i].duration)) < 0) {
+		syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
+		return 1;
+	    }
+	    if ((rc = xmlTextWriterEndElement(writer)) < 0) {
+		syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterEndElement");
+		return 1;
+	    }
+	}
+	if ((rc = xmlTextWriterEndElement(writer)) < 0) {
+	    syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterEndElement");
+	    return 1;
+	}
+
+	/* 
+	 * Close the element named RECIPE.
+	 */
+	if ((rc = xmlTextWriterEndElement(writer)) < 0) {
+	    syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterEndElement");
+	    return 1;
+	}
+    }
+    /* 
+     * Close the element named RECIPES.
+     */
+    if ((rc = xmlTextWriterEndElement(writer)) < 0) {
+	syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterEndElement");
+	return 1;
+    }
+
+    /*
+     * All done, close any open elements
+     */
+    if ((rc = xmlTextWriterEndDocument(writer)) < 0) {
+	syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterEndDocument");
+	return 1;
+    }
+    xmlFreeTextWriter(writer);
+
+    /*
+     * Now write the XML recipes
+     */
+    if (getenv((char *)"USER") == NULL) {
+	mypath = xstrcpy((char *)"/root");
+    } else {
+	mypath = xstrcpy(getenv((char *)"HOME"));
+    }
+    mypath = xstrcat(mypath, (char *)"/.brewco/etc/");
+    mkdirs(mypath, 0755);
+    mypath = xstrcat(mypath, (char *)"recipes.xml");
+
+    if (debug)
+	fprintf(stdout, "Writing %s\n", mypath);
+
+    if ((fp = fopen(mypath, "w")) == NULL) {
+	syslog(LOG_NOTICE, "could not rewrite %s", mypath);
+	free(mypath);
+	return 1;
+    }
+    free(mypath);
+
+    fprintf(fp, "%s", (const char *) buf->content);
+    fclose(fp);
+    xmlBufferFree(buf);
+
+    return 0;
+}
+
+
+
+int wrrecipes(void)
+{
+    int		rc;
+
+    rc = do_wrrecipes();
+    syslog(LOG_NOTICE, "Rewritten recipes, rc=%d", rc);
+    return rc;
+}
+
+
+
+int parseRecipe(xmlDocPtr doc, xmlNodePtr cur)
+{
+    xmlChar             *key;
+    xmlNodePtr		s1cur, s2cur;
+    a_recipe		*recipe, *tmp;
+    int                 i, j, ival;
+    float		fval;
+
+    recipe = (a_recipe *)malloc(sizeof(a_recipe));
+    memset(recipe, 0, sizeof(a_recipe));
+    recipe->next = NULL;
+
+    cur = cur->xmlChildrenNode;
+    while (cur != NULL) {
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"UUID"))) {
+	    recipe->uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"CODE"))) {
+	    recipe->code = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
+	    recipe->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"BOILTIME"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%d", &ival) == 1)
+		recipe->boiltime = ival;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"STARTTIME"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%d", &ival) == 1)
+		recipe->starttime = (time_t)ival;
+	    xmlFree(key);
+	}
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"ENDTIME"))) {
+	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
+	    if (sscanf((const char *)key, "%d", &ival) == 1)
+		recipe->endtime = (time_t)ival;
+	    xmlFree(key);
+	}
+fprintf(stdout, "cur %s\n", cur->name);
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"MASHSTEPS"))) {
+	    s1cur = cur->xmlChildrenNode;
+	    i = 0;
+	    while (s1cur != NULL) {
+fprintf(stdout, "  s1cur %s\n", s1cur->name);
+
+		if ((!xmlStrcmp(s1cur->name, (const xmlChar *)"MASHSTEP"))) {
+		    s2cur = s1cur->xmlChildrenNode;
+		    while (s2cur != NULL) {
+fprintf(stdout, "    s2cur %s\n", s2cur->name);
+			if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"NAME"))) {
+			    recipe->mash[i].name = (char *)xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
+			}
+			if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"MIN"))) {
+			    key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
+			    if (sscanf((const char *)key, "%d", &ival) == 1)
+				recipe->mash[i].min = ival;
+			    xmlFree(key);
+			}
+			if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"MAX"))) {
+			    key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
+			    if (sscanf((const char *)key, "%d", &ival) == 1)
+				recipe->mash[i].max = ival;
+			    xmlFree(key);
+			}
+			if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"CANSKIP"))) {
+			    key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
+			    for (j = 0; j < 2; j++) {
+				if (! xmlStrcmp(key, (const xmlChar *)SKIPYN[j])) {
+				    recipe->mash[i].canskip = j;
+				    break;
+				}
+			    }
+			    xmlFree(key);
+			}
+			if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"SETPOINT"))) {
+			    key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
+			    if (sscanf((const char *)key, "%f", &fval) == 1)
+				recipe->mash[i].setpoint = fval;
+			    xmlFree(key);
+			}
+			if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"SKIP"))) {
+			    key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
+			    for (j = 0; j < 2; j++) {
+				if (! xmlStrcmp(key, (const xmlChar *)SKIPYN[j])) {
+				    recipe->mash[i].skip = j;
+				    break;
+				}
+			    }
+			    xmlFree(key);
+			}
+			if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"DURATION"))) {
+			    key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
+			    if (sscanf((const char *)key, "%d", &ival) == 1)
+				recipe->mash[i].duration = ival;
+			    xmlFree(key);
+			}
+			s2cur = s2cur->next;
+		    }
+		    i++;
+		}
+		s1cur = s1cur->next;
+	    }
+	}
+
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HOPADDITIONS"))) {
+	    s1cur = cur->xmlChildrenNode;
+	    i = 0;
+	    while (s1cur != NULL) {
+fprintf(stdout, "  s1cur %s\n", s1cur->name);
+
+		if ((!xmlStrcmp(s1cur->name, (const xmlChar *)"HOPADDITION"))) {
+		    s2cur = s1cur->xmlChildrenNode;
+		    while (s2cur != NULL) {
+fprintf(stdout, "    s2cur %s\n", s2cur->name);
+			if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"NAME"))) {
+			    recipe->hops[i].name = (char *)xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
+			}
+			if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"BOILTIME"))) {
+			    key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
+			    if (sscanf((const char *)key, "%d", &ival) == 1)
+				recipe->hops[i].boiltime = ival;
+			    xmlFree(key);
+			}
+			s2cur = s2cur->next;
+		    }
+		    i++;
+		}
+		s1cur = s1cur->next;
+	    }
+	}
+
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HOPSTANDS"))) {
+	    s1cur = cur->xmlChildrenNode;
+	    i = 0;
+	    while (s1cur != NULL) {
+fprintf(stdout, "  s1cur %s\n", s1cur->name);
+
+		if ((!xmlStrcmp(s1cur->name, (const xmlChar *)"HOPSTAND"))) {
+		    s2cur = s1cur->xmlChildrenNode;
+		    while (s2cur != NULL) {
+fprintf(stdout, "    s2cur %s\n", s2cur->name);
+			if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"NAME"))) {
+			    recipe->hopstand[i].name = (char *)xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
+			}
+			if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"MIN"))) {
+			    key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
+			    if (sscanf((const char *)key, "%d", &ival) == 1)
+				recipe->hopstand[i].min = ival;
+			    xmlFree(key);
+			}
+			if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"MAX"))) {
+			    key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
+			    if (sscanf((const char *)key, "%d", &ival) == 1)
+				recipe->hopstand[i].max = ival;
+			    xmlFree(key);
+			}
+			if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"HOLD"))) {
+			    key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
+			    for (j = 0; j < 2; j++) {
+				if (! xmlStrcmp(key, (const xmlChar *)SKIPYN[j])) {
+				    recipe->hopstand[i].hold = j;
+				    break;
+				}
+			    }
+			    xmlFree(key);
+			}
+			if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"SETPOINT"))) {
+			    key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
+			    if (sscanf((const char *)key, "%f", &fval) == 1)
+				recipe->hopstand[i].setpoint = fval;
+			    xmlFree(key);
+			}
+			if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"SKIP"))) {
+			    key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
+			    for (j = 0; j < 2; j++) {
+				if (! xmlStrcmp(key, (const xmlChar *)SKIPYN[j])) {
+				    recipe->hopstand[i].skip = j;
+				    break;
+				}
+			    }
+			    xmlFree(key);
+			}
+			if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"DURATION"))) {
+			    key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
+			    if (sscanf((const char *)key, "%d", &ival) == 1)
+				recipe->hopstand[i].duration = ival;
+			    xmlFree(key);
+			}
+			s2cur = s2cur->next;
+		    }
+		    i++;
+		}
+		s1cur = s1cur->next;
+	    }
+	}
+	cur = cur->next;
+    }
+
+    if (recipes == NULL) {
+	recipes = recipe;
+    } else {
+	for (tmp = recipes; tmp; tmp = tmp->next) {
+	    if (tmp->next == NULL) {
+		tmp->next = recipe;
+		break;
+	    }
+	}
+    }
+
+    return 0;
+}
+
+
+
+int parseRecipes(xmlDocPtr doc, xmlNodePtr cur)
+{
+    cur = cur->xmlChildrenNode;
+    while (cur != NULL) {
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"RECIPE"))) {
+	    parseRecipe(doc, cur);
+	}
+	cur = cur->next;
+    }
+    return 0;
+}
+
+
+
+/*
+ * Returns:
+ *  0 - All is well, recipes loaded.
+ *  1 - Something went wrong
+ */
+int rdrecipes(void) 
+{
+    int		i;
+    char	*mypath;
+    xmlDocPtr	doc;
+    xmlNodePtr	cur;
+    a_recipe	*recipe;
+
+    syslog(LOG_NOTICE, "HOME='%s' USER='%s' LOGNAME='%s'", MBSE_SS(getenv((char *)"HOME")), MBSE_SS(getenv((char *)"USER")), MBSE_SS(getenv((char *)"LOGNAME")));
+
+    /*
+     * Search config file
+     */
+    if (getenv((char *)"USER") == NULL) {
+	mypath = xstrcpy((char *)"/root");
+    } else {
+    	mypath = xstrcpy(getenv((char *)"HOME"));
+    }
+    mypath = xstrcat(mypath, (char *)"/.brewco/etc/");
+    mkdirs(mypath, 0755);
+    mypath = xstrcat(mypath, (char *)"recipes.xml");
+
+    /*
+     * Free possible old recipes list
+     */
+    for (recipe = recipes; recipe; recipe = recipe->next) {
+	if (recipe->uuid)
+	    free(recipe->uuid);
+	if (recipe->code)
+	    free(recipe->code);
+	if (recipe->name)
+	    free(recipe->name);
+	for (i = 0; i < 8; i++)
+	    if (recipe->mash[i].name)
+		free(recipe->mash[i].name);
+	for (i = 0; i < 10; i++)
+	    if (recipe->hops[i].name)
+		free(recipe->hops[i].name);
+	for (i = 0; i < 3; i++)
+	    if (recipe->hopstand[i].name)
+		free(recipe->hopstand[i].name);
+	free(recipe);
+    }
+    recipes = NULL;
+
+    /*
+     * See if we have a recipes file.
+     */
+    if (file_exist(mypath, W_OK)) {
+	syslog(LOG_NOTICE, "rdrecipes: %s not found, good.", mypath);
+	free(mypath);
+	return 0;
+    }
+
+    if ((doc = xmlParseFile(mypath)) == NULL) {
+	syslog(LOG_NOTICE, "rdrecipes: %s not found, we may need some.", mypath);
+	free(mypath);
+	return 0;
+    }
+    syslog(LOG_NOTICE, "rdrecipes: using %s", mypath);
+
+    if ((cur = xmlDocGetRootElement(doc)) == NULL) {
+	syslog(LOG_NOTICE, "XML file %s empty.", mypath);
+	xmlFreeDoc(doc);
+	return 1;
+    }
+    if (xmlStrcmp(cur->name, (const xmlChar*)"BREWCO")) {
+	syslog(LOG_NOTICE, "XML file %s is not a valid configuration file.", mypath);
+	xmlFreeDoc(doc);
+	return 1;
+    }
+
+    /*
+     * Parse recipes
+     */
+    cur = cur->xmlChildrenNode;
+    while (cur != NULL) {
+	if ((!xmlStrcmp(cur->name, (const xmlChar *)"RECIPES"))) {
+	    parseRecipes(doc, cur);
+	}
+	cur = cur->next;
+    }
+    xmlFreeDoc(doc);
+
+    free(mypath);
+    mypath = NULL;
+
+    return 0;
+}
+
+
+

mercurial