Sun, 27 Jul 2014 21:04:57 +0200
Small fix
/***************************************************************************** * 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"); } }