brewco/rdrecipes.c

Sun, 27 Dec 2015 17:52:26 +0100

author
Michiel Broek <mbroek@mbse.eu>
date
Sun, 27 Dec 2015 17:52:26 +0100
changeset 477
9167ad4c2e77
parent 473
fdd30e935079
permissions
-rw-r--r--

Renamed Mash-in step to Prepare on the display. Don't run the pump when the mash is added. When preparing the mash, first heat the HLT, and then the MLT so that both have the chance to reach their target temperatures.

/*****************************************************************************
 * 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;
extern char	*etcpath;

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 "COOLTO", "%f", recipe->coolto)) < 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 ((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 "SKIP", "%s", recipe->hops[i].skip ? "YES":"NO")) < 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
     */
    mypath = xstrcpy(etcpath);
    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;
    recipe->coolto = 20.0;

    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 *)"COOLTO"))) {
	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
	    if (sscanf((const char *)key, "%f", &fval) == 1)
		recipe->coolto = fval;
	    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);
	}
	if ((!xmlStrcmp(cur->name, (const xmlChar *)"MASHSTEPS"))) {
	    s1cur = cur->xmlChildrenNode;
	    i = 0;
	    while (s1cur != NULL) {
		if ((!xmlStrcmp(s1cur->name, (const xmlChar *)"MASHSTEP"))) {
		    s2cur = s1cur->xmlChildrenNode;
		    while (s2cur != NULL) {
			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) {
		if ((!xmlStrcmp(s1cur->name, (const xmlChar *)"HOPADDITION"))) {
		    s2cur = s1cur->xmlChildrenNode;
		    while (s2cur != NULL) {
			if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"NAME"))) {
			    recipe->hops[i].name = (char *)xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
			}
			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->hops[i].skip = j;
				    break;
				}
			    }
			    xmlFree(key);
			}
			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) {
		if ((!xmlStrcmp(s1cur->name, (const xmlChar *)"HOPSTAND"))) {
		    s2cur = s1cur->xmlChildrenNode;
		    while (s2cur != NULL) {
			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;

    /*
     * Search config file
     */
    mypath = xstrcpy(etcpath);
    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