mash/beerxml.c

changeset 538
6d139c21e22c
parent 537
4eebab50993e
child 539
300b5c4cd977
--- a/mash/beerxml.c	Sun Jul 15 14:08:19 2018 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1531 +0,0 @@
-/*****************************************************************************
- * Copyright (C) 2014
- *   
- * 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 EC-65K; see the file COPYING.  If not, write to the Free
- * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
- *****************************************************************************/
-
-#include "mash.h"
-#include "beerxml.h"
-
-
-recipe_rec		*recipes = NULL;
-
-
-int parseStyle(xmlDocPtr, xmlNodePtr, style_rec **);
-int parseEquipment(xmlDocPtr, xmlNodePtr, equipment_rec **);
-int parseMashStep(xmlDocPtr, xmlNodePtr, mash_step **);
-int parseMashSteps(xmlDocPtr, xmlNodePtr, mash_step **);
-int parseMash(xmlDocPtr, xmlNodePtr, mash_profile **);
-int parseFermentable(xmlDocPtr, xmlNodePtr, fermentable_rec **);
-int parseFermentables(xmlDocPtr, xmlNodePtr, fermentable_rec **);
-
-
-
-
-/*
- * Parse style
- */
-int parseStyle(xmlDocPtr doc, xmlNodePtr cur, style_rec **style)
-{
-    xmlChar     *key;
-    style_rec   *item;
-    float       val;
-
-    item = (style_rec *)malloc(sizeof(style_rec));
-    item->name = item->category = item->category_number = item->style_letter = item-> style_guide =
-	    item->type = item->notes = item->profile = item->ingredients = item->examples = NULL;
-    item->og_min = item->og_max = item->fg_min = item->fg_max = item->ibu_min = item->ibu_max =
-	    item->color_min = item->color_max = item->carb_min = item->carb_max = 
-	    item->abv_min = item->abv_max = 0.0;
-
-    cur = cur->xmlChildrenNode;
-    while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VERSION"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (xmlStrcmp(key, (const xmlChar *)"1")) {
-		xmlFree(key);
-		return 1;
-	    }
-	    item->version = 1;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
-	    item->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"CATEGORY"))) {
-	    item->category = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"CATEGORY_NUMBER"))) {
-	    item->category_number = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"STYLE_LETTER"))) {
-	    item->style_letter = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"STYLE_GUIDE"))) {
-	    item->style_guide = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TYPE"))) {
-	    item->type = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"OG_MIN"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->og_min = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"OG_MAX"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->og_max = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"FG_MIN"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->fg_min = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"FG_MAX"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->fg_max = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"IBU_MIN"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->ibu_min = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"IBU_MAX"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->ibu_max = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"COLOR_MIN"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->color_min = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"COLOR_MAX"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->color_max = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"CARB_MIN"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->carb_min = val;
-	    xmlFree(key);
-	}               
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"CARB_MAX"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->carb_max = val;
-	    xmlFree(key); 
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"ABV_MIN"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->abv_min = val;
-	    xmlFree(key);
-	}              
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"ABV_MAX"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->abv_max = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NOTES"))) {
-	    item->notes = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROFILE"))) {
-	    item->profile = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"INGREDIENTS"))) {
-	    item->ingredients = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"EXAMPLES"))) {
-	    item->examples = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	cur = cur->next;
-    }
-
-    *style = item;
-    return 0;
-}
-
-
-
-/*
- * Parse equipment
- */
-int parseEquipment(xmlDocPtr doc, xmlNodePtr cur, equipment_rec **equipment)
-{
-    xmlChar     	*key;
-    equipment_rec	*item;
-    float       	val;
-
-    item = (equipment_rec *)malloc(sizeof(equipment_rec));
-    item->name = item->notes = NULL;
-    item->version = 0;
-    item->boil_size = item->batch_size = item->tun_volume = item->tun_weight = 
-	    item->tun_specific_heat = item->top_up_water = item->trub_chiller_loss = 
-	    item->evap_rate = item->boil_time = item->lauter_deadspace =
-	    item->top_up_kettle = item->hop_utilization = 0.0;
-    item->calc_boil_volume = FALSE;
-
-    cur = cur->xmlChildrenNode;
-    while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VERSION"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (xmlStrcmp(key, (const xmlChar *)"1")) {
-		xmlFree(key);
-		return 1;
-	    }
-	    xmlFree(key);
-	    item->version = 1;
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
-	    item->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"BOIL_SIZE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->boil_size = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"BATCH_SIZE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->batch_size = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TUN_VOLUME"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->tun_volume = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TUN_WEIGHT"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->tun_weight = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TUN_SPECIFIC_HEAT"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->tun_specific_heat = val;    
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TOP_UP_WATER"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->top_up_water = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TRUB_CHILLER_LOSS"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->trub_chiller_loss = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"EVAP_RATE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->evap_rate = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"BOIL_TIME"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->boil_time = val;
-	    xmlFree(key);        
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"CALC_BOIL_VOLUME"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (! xmlStrcmp(key, (const xmlChar *)"TRUE"))
-		item->calc_boil_volume = TRUE;
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"LAUTER_DEADSPACE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->lauter_deadspace = val;
-	    xmlFree(key);        
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HOP_UTILIZATION"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->hop_utilization = val;
-	    xmlFree(key);        
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NOTES"))) {
-	    item->notes = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	cur = cur->next;
-    }
-
-    *equipment = item;
-    return 0;
-}
-
-
-
-/*
- * Parse a Mash step and add it to the linked list
- */
-int parseMashStep(xmlDocPtr doc, xmlNodePtr cur, mash_step **mashstep)
-{
-    xmlChar     *key;
-    mash_step	*step, *tmp;
-    float	val;
-
-    cur = cur->xmlChildrenNode;
-
-    step = (mash_step *)malloc(sizeof(mash_step));
-    step->next = NULL;
-    step->name = NULL;
-    step->type = NULL;
-    step->infuse_amount = 0.0;
-    step->step_temp = 0.0;
-    step->end_temp = 0.0;
-    step->step_time = 0.0;
-    step->ramp_time = 0.0;
-    step->version = 0;
-
-    while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VERSION"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (xmlStrcmp(key, (const xmlChar *)"1")) {
-		xmlFree(key);
-		return 1;
-	    }
-	    step->version = 1;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
-	    step->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TYPE"))) {
-	    step->type = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"INFUSE_AMOUNT"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		step->infuse_amount = val;
-	    xmlFree(key);                           
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"STEP_TEMP"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		step->step_temp = val;
-	    xmlFree(key);                           
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"STEP_TIME"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		step->step_time = val;
-	    xmlFree(key);                           
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"END_TEMP"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		step->end_temp = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"RAMP_TIME"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		step->ramp_time = val;
-	    xmlFree(key);
-	}
-
-	cur = cur->next;
-    }
-	
-    if (*mashstep == NULL) {
-	*mashstep = step;
-    } else {
-	for (tmp = *mashstep; tmp; tmp = tmp->next) {
-	    if (tmp->next == NULL) {
-		tmp->next = step;
-		break;
-	    }
-	}
-    }
-    return 0;
-}
-
-
-
-/*
- * Parse all Mash steps
- */
-int parseMashSteps(xmlDocPtr doc, xmlNodePtr cur, mash_step **step)
-{
-    int		rc;
-
-    cur = cur->xmlChildrenNode;
-    while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"MASH_STEP"))) {
-	    if ((rc = parseMashStep(doc, cur, step)))
-		return 1;
-	}
-	cur = cur->next;
-    }
-    return 0;
-}
-
-
-
-/*
- * Parse Mash profile
- */
-int parseMash(xmlDocPtr doc, xmlNodePtr cur, mash_profile **mash)
-{
-    xmlChar     *key;
-    mash_profile	*mashprofile;
-    float	val;
-
-    mashprofile = (mash_profile *)malloc(sizeof(mash_profile));
-    mashprofile->name = NULL;
-    mashprofile->version = 0;
-    mashprofile->notes = NULL;
-    mashprofile->grain_temp = 0.0;
-    mashprofile->mash_steps = NULL;
-    mashprofile->tun_temp = 0.0;
-    mashprofile->sparge_temp = 0.0;
-    mashprofile->ph = 0.0;
-    mashprofile->tun_weight = 0.0;
-    mashprofile->tun_specific_heat = 0.0;
-    mashprofile->equip_adjust = FALSE;
-
-    cur = cur->xmlChildrenNode;
-    while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VERSION"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (xmlStrcmp(key, (const xmlChar *)"1")) {
-		xmlFree(key);
-		return 1;
-	    }
-	    mashprofile->version = 1;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
-	    mashprofile->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NOTES"))) {
-	    mashprofile->notes = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"GRAIN_TEMP"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		mashprofile->grain_temp = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TUN_TEMP"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		mashprofile->tun_temp = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"SPARGE_TEMP"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		mashprofile->sparge_temp = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PH"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		mashprofile->ph = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TUN_WEIGHT"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		mashprofile->tun_weight = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TUN_SPECIFIC_HEAT"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		mashprofile->tun_specific_heat = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"EQUIP_ADJUST"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (! xmlStrcmp(key, (const xmlChar *)"TRUE"))
-		mashprofile->equip_adjust = TRUE;
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"MASH_STEPS"))) {
-	    parseMashSteps(doc, cur, &(mashprofile)->mash_steps);
-	}
-	cur = cur->next;
-    }
-
-    *mash = mashprofile;
-    return 0;
-}
-
-
-
-/*
- * Parse fermentable
- */
-int parseFermentable(xmlDocPtr doc, xmlNodePtr cur, fermentable_rec **fr)
-{
-    xmlChar     	*key;
-    fermentable_rec	*item, *tmp;
-    float               val;
-
-    item = (fermentable_rec *)malloc(sizeof(fermentable_rec));
-    item->next = NULL;
-    item->name = item->type = item->notes = item->origin = item->supplier = NULL;
-    item->version = 0;
-    item->amount = item->yield = item->color = item->coarse_fine_diff = item->moisture = 
-	    item->diastatic_power = item->protein = item->max_in_batch = 0.0;
-    item->add_after_boil = item->recommend_mash = FALSE;
-
-    cur = cur->xmlChildrenNode;
-    while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VERSION"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (xmlStrcmp(key, (const xmlChar *)"1")) {
-		xmlFree(key);
-		return 1;
-	    }
-	    item->version = 1;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
-	    item->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NOTES"))) {
-	    item->notes = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TYPE"))) {
-	    item->type = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"ORIGIN"))) {
-	    item->origin = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"SUPPLIER"))) {
-	    item->supplier = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"AMOUNT"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->amount = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"YIELD"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->yield = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"COLOR"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->color = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"ADD_AFTER_BOIL"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (! xmlStrcmp(key, (const xmlChar *)"TRUE"))
-		item->add_after_boil = TRUE;
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"COARSE_FINE_DIFF"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->coarse_fine_diff = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"MOISTURE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->moisture = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"DIASTATIC_POWER"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->diastatic_power = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PROTEIN"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->protein = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"MAX_IN_BATCH"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->max_in_batch = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"RECOMMEND_MASH"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (! xmlStrcmp(key, (const xmlChar *)"TRUE"))
-		item->recommend_mash = TRUE;
-	}
-	cur = cur->next;
-    }
-
-    if (*fr == NULL) {
-	*fr = item;
-    } else {
-	for (tmp = *fr; tmp; tmp = tmp->next) {
-	    if (tmp->next == NULL) {
-		tmp->next = item;
-		break;
-	    }
-	}
-    }
-
-    return 0;
-}
-
-
-
-/*
- * Parse fermentables
- */
-int parseFermentables(xmlDocPtr doc, xmlNodePtr cur, fermentable_rec **fr)
-{
-    cur = cur->xmlChildrenNode;
-    while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"FERMENTABLE"))) {
-	    parseFermentable(doc, cur, fr);
-	}
-	cur = cur->next;
-    }
-    return 0;
-}
-
-
-
-/*
- * Parse hop
- */
-int parseHop(xmlDocPtr doc, xmlNodePtr cur, hop_rec **hr)
-{
-    xmlChar     *key;
-    hop_rec	*item, *tmp;
-    float       val;
-
-    item = (hop_rec *)malloc(sizeof(hop_rec));
-    item->next = NULL;
-    item->name = item->use = item->notes = item->type = item->form = 
-	    item->origin = item->substitutes = NULL;
-    item->version = 0;
-    item->alpha = item->amount = item->time = item->beta = item->hsi = 
-	    item->humulene = item->caryophyllene = item->cohumulone = item->myrcene = 0.0;
-
-    cur = cur->xmlChildrenNode;
-    while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VERSION"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (xmlStrcmp(key, (const xmlChar *)"1")) {
-		xmlFree(key);
-		return 1;
-	    }
-	    item->version = 1;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
-	    item->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"ALPHA"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->alpha = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"AMOUNT"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->amount = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"USE"))) {
-	    item->use = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TIME"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->time = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NOTES"))) {
-	    item->notes = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TYPE"))) {
-	    item->type = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"FORM"))) {
-	    item->form = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"BETA"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->beta = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HSI"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->hsi = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"ORIGIN"))) {
-	    item->origin = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"SUBSTITITES"))) {
-	    item->substitutes = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HUMULENE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->humulene = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"CARYOPHYLLENE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->caryophyllene = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"COHUMULONE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->cohumulone = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"MYRCENE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->myrcene = val;
-	    xmlFree(key);
-	}
-	cur = cur->next;
-    }
-
-    if (*hr == NULL) {
-	*hr = item;
-    } else {
-	for (tmp = *hr; tmp; tmp = tmp->next) {
-	    if (tmp->next == NULL) {
-		tmp->next = item;
-		break;
-	    }
-	}
-    }
-
-    return 0;
-}
-
-
-
-/*
- * Parse hops
- */
-int parseHops(xmlDocPtr doc, xmlNodePtr cur, hop_rec **hr)
-{
-    cur = cur->xmlChildrenNode;
-    while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HOP"))) {
-	    parseHop(doc, cur, hr);
-	}
-	cur = cur->next;
-    }
-    return 0;
-}
-
-
-
-/*
- * Parse Yeast
- */
-int parseYeast(xmlDocPtr doc, xmlNodePtr cur, yeast_rec **yr)
-{
-    xmlChar     *key;
-    yeast_rec	*item, *tmp;
-    float       val;
-    int		ival;
-
-    item = (yeast_rec *)malloc(sizeof(yeast_rec));
-    item->next = NULL;
-    item->name = item->type = item->form = item->laboratory = item->product_id = item->flocculation = item->notes = item->best_for = NULL;
-    item->amount = item->min_temperature = item->max_temperature = item->attenuation = 0.0;
-    item->amount_is_weight = item->add_to_secondary = FALSE;
-    item->version = item->times_cultured = item->max_reuse = 0;
-
-    cur = cur->xmlChildrenNode;
-    while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VERSION"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (xmlStrcmp(key, (const xmlChar *)"1")) {
-		xmlFree(key);
-		return 1;
-	    }
-	    item->version = 1;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
-	    item->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TYPE"))) {
-	    item->type = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"FORM"))) {
-	    item->form = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"AMOUNT"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->amount = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"AMOUNT_IS_WEIGHT"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (! xmlStrcmp(key, (const xmlChar *)"TRUE"))
-		item->amount_is_weight = TRUE;
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"LABORATORY"))) {
-	    item->laboratory = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PRODUCT_ID"))) {
-	    item->product_id = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"MIN_TEMPERATURE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->min_temperature = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"MAX_TEMPERATURE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->max_temperature = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"FLOCCULATION"))) {
-	    item->flocculation = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"ATTENUATION"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->attenuation = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NOTES"))) {
-	    item->notes = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"BEST_FOR"))) {
-	    item->best_for = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TIMES_CULTURED"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%d", &ival) == 1)
-		item->times_cultured = ival;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"MAX_REUSE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%d", &ival) == 1)
-		item->max_reuse = ival;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"ADD_TO_SECONDARY"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (! xmlStrcmp(key, (const xmlChar *)"TRUE"))
-		item->add_to_secondary = TRUE;
-	}
-	cur = cur->next;
-    }
-
-    if (*yr == NULL) {
-	*yr = item;
-    } else {
-	for (tmp = *yr; tmp; tmp = tmp->next) {
-	    if (tmp->next == NULL) {
-		tmp->next = item;
-		break;
-	    }
-	}
-    }
-
-    return 0;
-}
-
-
-
-/*
- * Parse Yeasts
- */
-int parseYeasts(xmlDocPtr doc, xmlNodePtr cur, yeast_rec **yr)
-{
-    cur = cur->xmlChildrenNode;
-    while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"YEAST"))) {
-	    parseYeast(doc, cur, yr);
-	}
-	cur = cur->next;
-    }
-    return 0;
-}
-
-
-
-/*
- * Parse Misc
- */
-int parseMisc(xmlDocPtr doc, xmlNodePtr cur, misc_rec **mr)
-{
-    xmlChar     *key;
-    misc_rec   	*item, *tmp;
-    float       val;
-
-    item = (misc_rec *)malloc(sizeof(misc_rec));
-    item->next = NULL;
-    item->name = item->type = item->use = item->use_for = item->notes = NULL;
-    item->amount = item->time = 0.0;
-    item->amount_is_weight = FALSE;
-    item->version = 0;
-
-    cur = cur->xmlChildrenNode;
-    while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VERSION"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (xmlStrcmp(key, (const xmlChar *)"1")) {
-		xmlFree(key);
-		return 1;
-	    }
-	    item->version = 1;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
-	    item->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TYPE"))) {
-	    item->type = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"USE"))) {
-	    item->use = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TIME"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->time = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"AMOUNT"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->amount = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"AMOUNT_IS_WEIGHT"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (! xmlStrcmp(key, (const xmlChar *)"TRUE"))
-		item->amount_is_weight = TRUE;
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"USE_FOR"))) {
-	    item->use_for = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NOTES"))) {
-	    item->notes = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	cur = cur->next;
-    }
-
-    if (*mr == NULL) {
-	*mr = item;
-    } else {
-	for (tmp = *mr; tmp; tmp = tmp->next) {
-	    if (tmp->next == NULL) {
-		tmp->next = item;
-		break;
-	    }
-	}
-    }
-
-    return 0;
-}
-
-
-
-/*
- * Parse Miscs
- */
-int parseMiscs(xmlDocPtr doc, xmlNodePtr cur, misc_rec **mr)
-{
-    cur = cur->xmlChildrenNode;
-    while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"MISC"))) {
-	    parseMisc(doc, cur, mr);
-	}
-	cur = cur->next;
-    }
-    return 0;
-}
-
-
-
-/*
- * Parse Water
- */
-int parseWater(xmlDocPtr doc, xmlNodePtr cur, water_rec **wr)
-{
-    xmlChar     *key;
-    water_rec   *item, *tmp;
-    float       val;
-
-    item = (water_rec *)malloc(sizeof(water_rec));
-    item->next = NULL;
-    item->name = item->notes = NULL;
-    item->amount = item->calcium = item->bicarbonate = item->sulfate = item->chloride = item->sodium = item->magnesium = item->ph = 0.0;
-    item->version = 0;
-
-    cur = cur->xmlChildrenNode;
-    while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"VERSION"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (xmlStrcmp(key, (const xmlChar *)"1")) {
-		xmlFree(key);
-		return 1;
-	    }
-	    item->version = 1;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
-	    item->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"AMOUNT"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->amount = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"CALCIUM"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->calcium = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"BICARBONATE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->bicarbonate = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"SULFATE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->sulfate = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"CHLORIDE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->chloride = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"SODIUM"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->sodium = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"MAGNESIUM"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->magnesium = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PH"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		item->ph = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NOTES"))) {
-	    item->notes = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	cur = cur->next;
-    }
-
-    if (*wr == NULL) {
-	*wr = item;
-    } else {
-	for (tmp = *wr; tmp; tmp = tmp->next) {
-	    if (tmp->next == NULL) {
-		tmp->next = item;
-		break;
-	    }
-	}
-    }
-
-    return 0;
-}
-
-
-
-/*
- * Parse Waters
- */
-int parseWaters(xmlDocPtr doc, xmlNodePtr cur, water_rec **wr)
-{
-    cur = cur->xmlChildrenNode;
-    while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"WATER"))) {
-	    parseWater(doc, cur, wr);
-	}
-	cur = cur->next;
-    }
-    return 0;
-}
-
-
-
-/*
- * Parse a recipe
- */
-void parseRecipe(xmlDocPtr doc, xmlNodePtr cur)
-{
-    xmlChar	*key;
-    recipe_rec	*recipe, *tmp;
-    float	val;
-    int		ival;
-
-    recipe = (recipe_rec *)malloc(sizeof(recipe_rec));
-    recipe->next = NULL;
-    recipe->name = NULL;
-    recipe->brewer = NULL;
-    recipe->asst_brewer = NULL;
-    recipe->type = NULL;
-    recipe->style = NULL;
-    recipe->equipment = NULL;
-    recipe->batch_size = 0.0;
-    recipe->boil_time = 0.0;
-    recipe->efficiency = 0.0;
-    recipe->hops = NULL;
-    recipe->fermentables = NULL;
-    recipe->miscs = NULL;
-    recipe->yeasts = NULL;
-    recipe->waters = NULL;
-    recipe->notes = NULL;
-    recipe->taste_notes = NULL;
-    recipe->taste_rating = 0.0;
-    recipe->og = 0.0;
-    recipe->fg = 0.0;
-    recipe->fermentation_stages = 0;
-    recipe->primary_age = recipe->secondary_age = recipe->tertiary_age = recipe->age = 0;
-    recipe->primary_temp = recipe->secondary_temp = recipe->tertiary_temp = recipe->age_temp = 0.0;
-    recipe->date = NULL;
-    recipe->carbonation = 0.0;
-    recipe->forced_carbonation = FALSE;
-    recipe->priming_sugar_name = NULL;
-    recipe->carbonation_temp = 0.0;
-    recipe->priming_sugar_equiv = recipe->keg_priming_factor = 0.0;
-
-    cur = cur->xmlChildrenNode;
-    while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
-	    recipe->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TYPE"))) {
-	    recipe->type = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"STYLE"))) {
-	    parseStyle(doc, cur, &(recipe)->style);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"EQUIPMENT"))) {
-	    parseEquipment(doc, cur, &(recipe)->equipment);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"BREWER"))) {
-	    recipe->brewer = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"ASST_BREWER"))) {
-	    recipe->asst_brewer = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"BATCH_SIZE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		recipe->batch_size = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"BOIL_SIZE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		recipe->boil_size = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"BOIL_TIME"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		recipe->boil_time = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"EFFICIENCY"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		recipe->efficiency = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"HOPS"))) {
-	    parseHops(doc, cur, &(recipe)->hops);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"FERMENTABLES"))) {
-	    parseFermentables(doc, cur, &(recipe)->fermentables);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"MISCS"))) {
-	    parseMiscs(doc, cur, &(recipe)->miscs);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"YEASTS"))) {
-	    parseYeasts(doc, cur, &(recipe)->yeasts);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"WATERS"))) {
-	    parseWaters(doc, cur, &(recipe)->waters);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"MASH"))) {
-	    parseMash(doc, cur, &(recipe)->mash);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"NOTES"))) {
-	    recipe->notes = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TASTE_NOTES"))) {
-	    recipe->taste_notes = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TASTE_RATING"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		recipe->taste_rating = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"OG"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		recipe->og = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"FG"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		recipe->fg = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"FERMENTATION_STAGES"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%d", &ival) == 1)
-		recipe->fermentation_stages = ival;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PRIMARY_AGE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%d", &ival) == 1)
-		recipe->primary_age = ival;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PRIMARY_TEMP"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		recipe->primary_temp = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"SECONDARY_AGE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%d", &ival) == 1)
-		recipe->secondary_age = ival;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"SECONDARY_TEMP"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		recipe->secondary_temp = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TERTIARY_AGE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%d", &ival) == 1)
-		recipe->tertiary_age = ival;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"TERTIARY_TEMP"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		recipe->tertiary_temp = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"AGE"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%d", &ival) == 1)
-		recipe->age = ival;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"AGE_TEMP"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		recipe->age_temp = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"DATE"))) {
-	    recipe->date = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"CARBONATION"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		recipe->carbonation = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"FORCED_CARBONATION"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (! xmlStrcmp(key, (const xmlChar *)"TRUE"))
-		recipe->forced_carbonation = TRUE;
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PRIMING_SUGAR_NAME"))) {
-	    recipe->priming_sugar_name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"CARBONATION_TEMP"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		recipe->carbonation_temp = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"PRIMING_SUGAR_EQUIV"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		recipe->priming_sugar_equiv = val;
-	    xmlFree(key);
-	}
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"KEG_PRIMING_FACTOR"))) {
-	    key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
-	    if (sscanf((const char *)key, "%f", &val) == 1)
-		recipe->keg_priming_factor = val;
-	    xmlFree(key);
-	}
-	cur = cur->next;
-    }
-
-    if (recipes == NULL) {
-	recipes = recipe;
-    } else {
-	for (tmp = recipes; tmp; tmp = tmp->next) {
-	    if (tmp->next == NULL) {
-		tmp->next = recipe;
-		break;
-	    }
-	}
-    }
-}
-
-
-
-int parseBeerXML(char *docname)
-{
-    xmlDocPtr		doc;
-    xmlNodePtr		cur;
-
-    if ((doc = xmlParseFile(docname)) == NULL) {
-	fprintf(stderr, "XML file %s errors.\n", docname);
-	return 1;
-    }
-
-    if ((cur = xmlDocGetRootElement(doc)) == NULL) {
-	fprintf(stderr, "XML file %s empty.\n", docname);
-	xmlFreeDoc(doc);
-	return 1;
-    }
-
-    if (xmlStrcmp(cur->name, (const xmlChar*)"RECIPES")) {
-	fprintf(stderr, "XML file %s is not a BeerXML file.\n", docname);
-	xmlFreeDoc(doc);
-	return 1;
-    }
-
-    /*
-     * Parse all recipes
-     */
-    cur = cur->xmlChildrenNode;
-    while (cur != NULL) {
-	if ((!xmlStrcmp(cur->name, (const xmlChar *)"RECIPE"))) {
-	    parseRecipe(doc, cur);
-	}
-	cur = cur->next;
-    }
-
-    xmlFreeDoc(doc);
-    return 0;
-}
-
-
-
-/*
- * For debugging purposes, dump the recipes
- */
-void printBeerXML(void)
-{
-    recipe_rec		*tmp0;
-    mash_step           *tmp1;
-    fermentable_rec     *tmp2;
-    equipment_rec	*tmp3;
-    style_rec		*tmp4;
-    hop_rec		*tmp5;
-    yeast_rec		*tmp6;
-    misc_rec		*tmp7;
-    water_rec		*tmp8;
-    int			mashstep = 0;
-    float               grain_weight = 0.0, water_grain_ratio, tun_water = 0.0, temp;
-
-    for (tmp0 = recipes; tmp0; tmp0 = tmp0->next) {
-	printf("--------------------------------------------------------------------------------\n");
-    	printf("Recipe:     %s\n", tmp0->name);
-    	printf("Type:       %s\n", tmp0->type);
-	if (tmp0->notes)
-	    printf("Notes:      %s\n", tmp0->notes);
-	if (tmp0->brewer || tmp0->asst_brewer)
-    	    printf("Brewer:     %s  Assistent brewer: %s\n", tmp0->brewer, tmp0->asst_brewer);
-	printf("Batch size: %5.1f  Boil time:  %5.1f  Efficiency: %5.1f\n", tmp0->batch_size, tmp0->boil_time, tmp0->efficiency);
-	printf("Taste rate: %5.1f  Taste notes: %s\n", tmp0->taste_rating, tmp0->taste_notes);
-	printf("Original G: %5.3f  Final G:    %5.3f\n", tmp0->og, tmp0->fg);
-    	printf("\n");
-
-	if (tmp0->equipment) {
-	    tmp3 = tmp0->equipment;
-	    printf("Equipment:  %s\n", tmp3->name);
-	    if (tmp3->notes)
-	    	printf("  Notes:     %s\n", tmp3->notes);
-	    printf("  Boil size:  %5.1f  Batch size:   %5.1f  Boil time:        %5.1f\n", tmp3->boil_size, tmp3->batch_size, tmp3->boil_time);
-	    printf("  Tun volume: %5.1f  Tun weight:   %5.1f  Specific heat:    %5.1f\n", tmp3->tun_volume, tmp3->tun_weight, tmp3->tun_specific_heat);
-	    printf("  TopUp:      %5.1f  Chiller loss: %5.1f  Evaporation rate: %5.1f\n", tmp3->top_up_water, tmp3->trub_chiller_loss, tmp3->evap_rate);
-	    printf("  Tun loss:   %5.1f  TopUp kettle: %5.1f  Hop utilization:  %5.1f\n", tmp3->lauter_deadspace, tmp3->top_up_kettle, tmp3->hop_utilization);
-	    printf("  CalcBoilVol:  %s\n", tmp3->calc_boil_volume ? "YES":"NO");
-	    printf("\n");
-	}
-
-	if (tmp0->style) {
-	    tmp4 = tmp0->style;
-	    printf("Style:      %s-%s Type:   %s\n", tmp4->style_letter, tmp4->name, tmp4->type); 
-	    if (tmp4->category || tmp4->category_number || tmp4->style_guide)
-	    	printf(" Category:  %s    Cat nr: %s  Guide: %s\n", tmp4->category, tmp4->category_number, tmp4->style_guide);
-	    printf("  OG:        %5.3f - %5.3f\n", tmp4->og_min, tmp4->og_max);
-	    printf("  FG:        %5.3f - %5.3f\n", tmp4->fg_min, tmp4->fg_max);
-	    printf("  Bittern:   %5.1f - %5.1f IBU\n", tmp4->ibu_min, tmp4->ibu_max);
-	    printf("  Color:     %5.1f - %5.1f SRM\n", tmp4->color_min, tmp4->color_max);
-	    printf("  Carb:      %5.1f - %5.1f V-CO2\n", tmp4->carb_min, tmp4->carb_max);
-	    printf("  ABV:       %5.1f - %5.1f %%\n", tmp4->abv_min, tmp4->abv_max);
-	    if (tmp4->notes)
-	    	printf("  Notes:     %s\n", tmp4->notes);
-	    if (tmp4->profile)
-	    	printf("  Profile:   %s\n", tmp4->profile);
-	    if (tmp4->examples)
-	    	printf("  Examples:  %s\n", tmp4->examples);
-	    printf("\n");
-	}
-
-    	printf("Fermentables:\n");
-    	printf("  Type         Name                       Kg    Mash  Moist\n");
-    	for (tmp2 = tmp0->fermentables; tmp2; tmp2 = tmp2->next) {
-	    printf("  %-12s %-25s %6.3f %-5s %5.1f\n", tmp2->type, tmp2->name, tmp2->amount,
-			tmp2->recommend_mash ? "TRUE":"FALSE", tmp2->moisture);
-	    if (tmp2->recommend_mash)
-	    	grain_weight += tmp2->amount;
-        }
-    	printf("\n");
-
-	if (tmp0->hops) {
-	    printf("Hops:\n");
-	    //        123456789 1234567890 1234567890123456789012345 123456 12345 12345
-	    printf("  Type      Use        Name                          Kg  Time Alpha\n");
-	    for (tmp5 = tmp0->hops; tmp5; tmp5 = tmp5->next) {
-	    	printf("  %-9s %-10s %-25s %6.3f %5.1f %5.1f\n", tmp5->type, tmp5->use, tmp5->name, tmp5->amount, tmp5->time, tmp5->alpha);
-	    }
-	    printf("\n");
-	}
-
-	if (tmp0->miscs) {
-	    printf("Miscs:\n");
-	    //        12345678901 123456789 1234567890123456789012345 123456 12345 12345
-	    printf("  Type        Use       Name                          Kg  Time\n");
-	    for (tmp7 = tmp0->miscs; tmp7; tmp7 = tmp7->next) {
-		printf("  %-11s %-9s %-25s %6.3f %5.1f\n", tmp7->type, tmp7->use, tmp7->name, tmp7->amount, tmp7->time);
-	    }
-	    printf("\n");
-	}
-
-	if (tmp0->waters) {
-	    printf("Wateren:\n");
-	    //        1234567890123456789012345 12345 12345 1234...
-	    printf("  Name                       Ltrs    PH Notes\n");
-	    for (tmp8 = tmp0->waters; tmp8; tmp8 = tmp8->next) {
-		printf("  %-25s %5.1f %5.1f %s\n", tmp8->name, tmp8->amount, tmp8->ph, tmp8->notes);
-	    }
-	    printf("\n");
-	}
-
-    	printf("Mash profile:   %s\n", tmp0->mash->name);
-	if (tmp0->mash->notes)
-    	    printf("  Notes:        %s\n", tmp0->mash->notes);
-    	printf("  Grain temp:  %5.1f   Tun temp:   %5.1f    Sparge temp:       %5.1f\n", tmp0->mash->grain_temp, tmp0->mash->tun_temp, tmp0->mash->sparge_temp);
-    	printf("  PH:          %5.1f   Tun weight: %6.2f   Tun specific heat: %6.2f\n", tmp0->mash->ph, tmp0->mash->tun_weight, tmp0->mash->tun_specific_heat);
-    	printf("  Equip adjust: %s\n", tmp0->mash->equip_adjust ? "TRUE":"FALSE");
-    	printf("\n");
-
-	if (tmp0->mash->mash_steps) {
-    	    mashstep = 0;
-    	    printf("st Name             Type          Temp  Endtmp Dur Rmp Inf/Dec  L/Kg\n");
-    	    for (tmp1 = tmp0->mash->mash_steps; tmp1; tmp1 = tmp1->next) {
-	    	mashstep++;
-	    	tun_water += tmp1->infuse_amount;
-	    	water_grain_ratio = tun_water / grain_weight;
-	    	temp = tmp1->infuse_amount;
-//	    	if ((tmp1->infuse_amount == 0.0) && (tmp1->decotion_amt > 0.0))
-//		    temp = tmp1->decotion_amt;
-	    	printf("%2d %-16s %-12s %6.1f %6.1f %3.0f %3.0f %6.1f %6.2f\n", mashstep, tmp1->name, tmp1->type, 
-			tmp1->step_temp, tmp1->end_temp, tmp1->step_time, tmp1->ramp_time, temp, water_grain_ratio);
-            }
-	    printf("\n");
-	}
-
-	if (tmp0->yeasts) {
-	    for (tmp6 = tmp0->yeasts; tmp6; tmp6 = tmp6->next) {
-		printf("Yeast:       %s\n", tmp6->name);
-		printf("  Type:      %-20s Form:       %-20s Amount:      %7.4f %s\n", 
-				tmp6->type, tmp6->form, tmp6->amount,  tmp6->amount_is_weight ? "Kg":"L");
-		printf("  Lab:       %-20s Product id: %-20s Flocculation: %s\n", tmp6->laboratory, tmp6->product_id, tmp6->flocculation);
-		printf("  Min temp: %5.1f                 Max temp:  %5.1f                 Attenuation: %5.1f\n", 
-				tmp6->min_temperature, tmp6->max_temperature, tmp6->attenuation);
-		if (tmp6->notes)
-		    printf("  Notes:     %s\n", tmp6->notes);
-		printf("\n");
-	    }
-	}
-
-	printf("\n");
-    }
-}
-
-

mercurial