brewco/rdrecipes.c

changeset 487
d5bc44183aa4
parent 486
5a237a99a793
child 488
bee1f70fb42b
equal deleted inserted replaced
486:5a237a99a793 487:d5bc44183aa4
1 /*****************************************************************************
2 * Copyright (C) 2015
3 *
4 * Michiel Broek <mbroek at mbse dot eu>
5 *
6 * This file is part of the mbsePi-apps
7 *
8 * This is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * mbsePi-apps is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with ThermFerm; see the file COPYING. If not, write to the Free
20 * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
21 *****************************************************************************/
22
23 #include "brewco.h"
24 #include "rdrecipes.h"
25 #include "util.h"
26 #include "xutil.h"
27
28 extern int debug;
29 extern char *etcpath;
30
31 a_recipe *recipes = NULL;
32
33
34 const char SKIPYN[2][4] = { "NO", "YES" };
35
36
37 #define MY_ENCODING "utf-8"
38
39
40 int do_wrrecipes(void);
41 int do_wrrecipes(void)
42 {
43 int i, rc = 0;
44 FILE *fp;
45 char *mypath = NULL;
46 a_recipe *recipe;
47 xmlTextWriterPtr writer;
48 xmlBufferPtr buf;
49
50 /*
51 * Create a new XML buffer, to which the XML document will be written
52 */
53 if ((buf = xmlBufferCreate()) == NULL) {
54 syslog(LOG_NOTICE, "wrrecipes: error creating the xml buffer");
55 return 1;
56 }
57
58 /*
59 * Create a new XmlWriter for memory, with no compression.
60 */
61 if ((writer = xmlNewTextWriterMemory(buf, 0)) == NULL) {
62 syslog(LOG_NOTICE, "wrrecipes: error creating the xml writer");
63 return 1;
64 }
65
66 /*
67 * Use indentation instead of one long line
68 */
69 if ((rc = xmlTextWriterSetIndent(writer, 2)) < 0) {
70 syslog(LOG_NOTICE, "wrrecipes: error setting Indent");
71 return 1;
72 }
73
74 /*
75 * Start the document with the xml default for the version,
76 * encoding ISO 8859-1 and the default for the standalone
77 * declaration.
78 */
79 if ((rc = xmlTextWriterStartDocument(writer, NULL, MY_ENCODING, NULL)) < 0) {
80 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterStartDocument");
81 return 1;
82 }
83
84 /*
85 * Start an element named "BREWCO". Since thist is the first
86 * element, this will be the root element of the document.
87 */
88 if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "BREWCO")) < 0) {
89 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterStartElement");
90 return 1;
91 }
92
93 if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "RECIPES")) < 0) {
94 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterStartElement");
95 return 1;
96 }
97
98 for (recipe = recipes; recipe; recipe = recipe->next) {
99
100 if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "RECIPE")) < 0) {
101 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterStartElement");
102 return 1;
103 }
104
105 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "UUID", "%s", recipe->uuid)) < 0) {
106 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
107 return 1;
108 }
109 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "CODE", "%s", recipe->code)) < 0) {
110 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
111 return 1;
112 }
113 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", recipe->name)) < 0) {
114 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
115 return 1;
116 }
117 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "BOILTIME", "%d", recipe->boiltime)) < 0) {
118 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
119 return 1;
120 }
121 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "COOLTO", "%f", recipe->coolto)) < 0) {
122 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
123 return 1;
124 }
125 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "STARTTIME", "%d", (int)recipe->starttime)) < 0) {
126 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
127 return 1;
128 }
129 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "ENDTIME", "%d", (int)recipe->endtime)) < 0) {
130 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
131 return 1;
132 }
133
134 /*
135 * 8 Mash steps
136 */
137 if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "MASHSTEPS")) < 0) {
138 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterStartElement");
139 return 1;
140 }
141 for (i =0; i < 8; i++) {
142 if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "MASHSTEP")) < 0) {
143 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterStartElement");
144 return 1;
145 }
146 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", recipe->mash[i].name)) < 0) {
147 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
148 return 1;
149 }
150 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MIN", "%d", recipe->mash[i].min)) < 0) {
151 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
152 return 1;
153 }
154 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MAX", "%d", recipe->mash[i].max)) < 0) {
155 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
156 return 1;
157 }
158 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "CANSKIP", "%s", recipe->mash[i].canskip ? "YES":"NO")) < 0) {
159 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
160 return 1;
161 }
162 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "SETPOINT", "%f", recipe->mash[i].setpoint)) < 0) {
163 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
164 return 1;
165 }
166 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "SKIP", "%s", recipe->mash[i].skip ? "YES":"NO")) < 0) {
167 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
168 return 1;
169 }
170 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "DURATION", "%d", recipe->mash[i].duration)) < 0) {
171 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
172 return 1;
173 }
174 if ((rc = xmlTextWriterEndElement(writer)) < 0) {
175 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterEndElement");
176 return 1;
177 }
178 }
179 if ((rc = xmlTextWriterEndElement(writer)) < 0) {
180 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterEndElement");
181 return 1;
182 }
183
184 /*
185 * 10 Hop additions
186 */
187 if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "HOPADDITIONS")) < 0) {
188 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterStartElement");
189 return 1;
190 }
191 for (i = 0; i < 10; i++) {
192 if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "HOPADDITION")) < 0) {
193 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterStartElement");
194 return 1;
195 }
196 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", recipe->hops[i].name)) < 0) {
197 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
198 return 1;
199 }
200 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "SKIP", "%s", recipe->hops[i].skip ? "YES":"NO")) < 0) {
201 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
202 return 1;
203 }
204 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "BOILTIME", "%d", recipe->hops[i].boiltime)) < 0) {
205 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
206 return 1;
207 }
208 if ((rc = xmlTextWriterEndElement(writer)) < 0) {
209 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterEndElement");
210 return 1;
211 }
212 }
213 if ((rc = xmlTextWriterEndElement(writer)) < 0) {
214 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterEndElement");
215 return 1;
216 }
217
218 /*
219 * 3 Hop stands
220 */
221 if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "HOPSTANDS")) < 0) {
222 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterStartElement");
223 return 1;
224 }
225 for (i = 0; i < 3; i++) {
226 if ((rc = xmlTextWriterStartElement(writer, BAD_CAST "HOPSTAND")) < 0) {
227 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterStartElement");
228 return 1;
229 }
230 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "NAME", "%s", recipe->hopstand[i].name)) < 0) {
231 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
232 return 1;
233 }
234 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MIN", "%d", recipe->hopstand[i].min)) < 0) {
235 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
236 return 1;
237 }
238 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "MAX", "%d", recipe->hopstand[i].max)) < 0) {
239 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
240 return 1;
241 }
242 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "HOLD", "%s", recipe->hopstand[i].hold ? "YES":"NO")) < 0) {
243 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
244 return 1;
245 }
246 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "SETPOINT", "%f", recipe->hopstand[i].setpoint)) < 0) {
247 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
248 return 1;
249 }
250 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "SKIP", "%s", recipe->hopstand[i].skip ? "YES":"NO")) < 0) {
251 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
252 return 1;
253 }
254 if ((rc = xmlTextWriterWriteFormatElement(writer, BAD_CAST "DURATION", "%d", recipe->hopstand[i].duration)) < 0) {
255 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterWriteFormatElement");
256 return 1;
257 }
258 if ((rc = xmlTextWriterEndElement(writer)) < 0) {
259 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterEndElement");
260 return 1;
261 }
262 }
263 if ((rc = xmlTextWriterEndElement(writer)) < 0) {
264 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterEndElement");
265 return 1;
266 }
267
268 /*
269 * Close the element named RECIPE.
270 */
271 if ((rc = xmlTextWriterEndElement(writer)) < 0) {
272 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterEndElement");
273 return 1;
274 }
275 }
276 /*
277 * Close the element named RECIPES.
278 */
279 if ((rc = xmlTextWriterEndElement(writer)) < 0) {
280 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterEndElement");
281 return 1;
282 }
283
284 /*
285 * All done, close any open elements
286 */
287 if ((rc = xmlTextWriterEndDocument(writer)) < 0) {
288 syslog(LOG_NOTICE, "wrrecipes: error at xmlTextWriterEndDocument");
289 return 1;
290 }
291 xmlFreeTextWriter(writer);
292
293 /*
294 * Now write the XML recipes
295 */
296 mypath = xstrcpy(etcpath);
297 mypath = xstrcat(mypath, (char *)"recipes.xml");
298
299 if (debug)
300 fprintf(stdout, "Writing %s\n", mypath);
301
302 if ((fp = fopen(mypath, "w")) == NULL) {
303 syslog(LOG_NOTICE, "could not rewrite %s", mypath);
304 free(mypath);
305 return 1;
306 }
307 free(mypath);
308
309 fprintf(fp, "%s", (const char *) buf->content);
310 fclose(fp);
311 xmlBufferFree(buf);
312
313 return 0;
314 }
315
316
317
318 int wrrecipes(void)
319 {
320 int rc;
321
322 rc = do_wrrecipes();
323 syslog(LOG_NOTICE, "Rewritten recipes, rc=%d", rc);
324 return rc;
325 }
326
327
328
329 int parseRecipe(xmlDocPtr doc, xmlNodePtr cur)
330 {
331 xmlChar *key;
332 xmlNodePtr s1cur, s2cur;
333 a_recipe *recipe, *tmp;
334 int i, j, ival;
335 float fval;
336
337 recipe = (a_recipe *)malloc(sizeof(a_recipe));
338 memset(recipe, 0, sizeof(a_recipe));
339 recipe->next = NULL;
340 recipe->coolto = 20.0;
341
342 cur = cur->xmlChildrenNode;
343 while (cur != NULL) {
344 if ((!xmlStrcmp(cur->name, (const xmlChar *)"UUID"))) {
345 recipe->uuid = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
346 }
347 if ((!xmlStrcmp(cur->name, (const xmlChar *)"CODE"))) {
348 recipe->code = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
349 }
350 if ((!xmlStrcmp(cur->name, (const xmlChar *)"NAME"))) {
351 recipe->name = (char *)xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
352 }
353 if ((!xmlStrcmp(cur->name, (const xmlChar *)"BOILTIME"))) {
354 key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
355 if (sscanf((const char *)key, "%d", &ival) == 1)
356 recipe->boiltime = ival;
357 xmlFree(key);
358 }
359 if ((!xmlStrcmp(cur->name, (const xmlChar *)"COOLTO"))) {
360 key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
361 if (sscanf((const char *)key, "%f", &fval) == 1)
362 recipe->coolto = fval;
363 xmlFree(key);
364 }
365 if ((!xmlStrcmp(cur->name, (const xmlChar *)"STARTTIME"))) {
366 key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
367 if (sscanf((const char *)key, "%d", &ival) == 1)
368 recipe->starttime = (time_t)ival;
369 xmlFree(key);
370 }
371 if ((!xmlStrcmp(cur->name, (const xmlChar *)"ENDTIME"))) {
372 key = xmlNodeListGetString(doc, cur->xmlChildrenNode, 1);
373 if (sscanf((const char *)key, "%d", &ival) == 1)
374 recipe->endtime = (time_t)ival;
375 xmlFree(key);
376 }
377 if ((!xmlStrcmp(cur->name, (const xmlChar *)"MASHSTEPS"))) {
378 s1cur = cur->xmlChildrenNode;
379 i = 0;
380 while (s1cur != NULL) {
381 if ((!xmlStrcmp(s1cur->name, (const xmlChar *)"MASHSTEP"))) {
382 s2cur = s1cur->xmlChildrenNode;
383 while (s2cur != NULL) {
384 if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"NAME"))) {
385 recipe->mash[i].name = (char *)xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
386 }
387 if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"MIN"))) {
388 key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
389 if (sscanf((const char *)key, "%d", &ival) == 1)
390 recipe->mash[i].min = ival;
391 xmlFree(key);
392 }
393 if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"MAX"))) {
394 key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
395 if (sscanf((const char *)key, "%d", &ival) == 1)
396 recipe->mash[i].max = ival;
397 xmlFree(key);
398 }
399 if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"CANSKIP"))) {
400 key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
401 for (j = 0; j < 2; j++) {
402 if (! xmlStrcmp(key, (const xmlChar *)SKIPYN[j])) {
403 recipe->mash[i].canskip = j;
404 break;
405 }
406 }
407 xmlFree(key);
408 }
409 if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"SETPOINT"))) {
410 key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
411 if (sscanf((const char *)key, "%f", &fval) == 1)
412 recipe->mash[i].setpoint = fval;
413 xmlFree(key);
414 }
415 if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"SKIP"))) {
416 key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
417 for (j = 0; j < 2; j++) {
418 if (! xmlStrcmp(key, (const xmlChar *)SKIPYN[j])) {
419 recipe->mash[i].skip = j;
420 break;
421 }
422 }
423 xmlFree(key);
424 }
425 if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"DURATION"))) {
426 key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
427 if (sscanf((const char *)key, "%d", &ival) == 1)
428 recipe->mash[i].duration = ival;
429 xmlFree(key);
430 }
431 s2cur = s2cur->next;
432 }
433 i++;
434 }
435 s1cur = s1cur->next;
436 }
437 }
438
439 if ((!xmlStrcmp(cur->name, (const xmlChar *)"HOPADDITIONS"))) {
440 s1cur = cur->xmlChildrenNode;
441 i = 0;
442 while (s1cur != NULL) {
443 if ((!xmlStrcmp(s1cur->name, (const xmlChar *)"HOPADDITION"))) {
444 s2cur = s1cur->xmlChildrenNode;
445 while (s2cur != NULL) {
446 if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"NAME"))) {
447 recipe->hops[i].name = (char *)xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
448 }
449 if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"SKIP"))) {
450 key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
451 for (j = 0; j < 2; j++) {
452 if (! xmlStrcmp(key, (const xmlChar *)SKIPYN[j])) {
453 recipe->hops[i].skip = j;
454 break;
455 }
456 }
457 xmlFree(key);
458 }
459 if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"BOILTIME"))) {
460 key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
461 if (sscanf((const char *)key, "%d", &ival) == 1)
462 recipe->hops[i].boiltime = ival;
463 xmlFree(key);
464 }
465 s2cur = s2cur->next;
466 }
467 i++;
468 }
469 s1cur = s1cur->next;
470 }
471 }
472
473 if ((!xmlStrcmp(cur->name, (const xmlChar *)"HOPSTANDS"))) {
474 s1cur = cur->xmlChildrenNode;
475 i = 0;
476 while (s1cur != NULL) {
477 if ((!xmlStrcmp(s1cur->name, (const xmlChar *)"HOPSTAND"))) {
478 s2cur = s1cur->xmlChildrenNode;
479 while (s2cur != NULL) {
480 if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"NAME"))) {
481 recipe->hopstand[i].name = (char *)xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
482 }
483 if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"MIN"))) {
484 key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
485 if (sscanf((const char *)key, "%d", &ival) == 1)
486 recipe->hopstand[i].min = ival;
487 xmlFree(key);
488 }
489 if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"MAX"))) {
490 key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
491 if (sscanf((const char *)key, "%d", &ival) == 1)
492 recipe->hopstand[i].max = ival;
493 xmlFree(key);
494 }
495 if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"HOLD"))) {
496 key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
497 for (j = 0; j < 2; j++) {
498 if (! xmlStrcmp(key, (const xmlChar *)SKIPYN[j])) {
499 recipe->hopstand[i].hold = j;
500 break;
501 }
502 }
503 xmlFree(key);
504 }
505 if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"SETPOINT"))) {
506 key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
507 if (sscanf((const char *)key, "%f", &fval) == 1)
508 recipe->hopstand[i].setpoint = fval;
509 xmlFree(key);
510 }
511 if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"SKIP"))) {
512 key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
513 for (j = 0; j < 2; j++) {
514 if (! xmlStrcmp(key, (const xmlChar *)SKIPYN[j])) {
515 recipe->hopstand[i].skip = j;
516 break;
517 }
518 }
519 xmlFree(key);
520 }
521 if ((!xmlStrcmp(s2cur->name, (const xmlChar *)"DURATION"))) {
522 key = xmlNodeListGetString(doc, s2cur->xmlChildrenNode, 1);
523 if (sscanf((const char *)key, "%d", &ival) == 1)
524 recipe->hopstand[i].duration = ival;
525 xmlFree(key);
526 }
527 s2cur = s2cur->next;
528 }
529 i++;
530 }
531 s1cur = s1cur->next;
532 }
533 }
534 cur = cur->next;
535 }
536
537 if (recipes == NULL) {
538 recipes = recipe;
539 } else {
540 for (tmp = recipes; tmp; tmp = tmp->next) {
541 if (tmp->next == NULL) {
542 tmp->next = recipe;
543 break;
544 }
545 }
546 }
547
548 return 0;
549 }
550
551
552
553 int parseRecipes(xmlDocPtr doc, xmlNodePtr cur)
554 {
555 cur = cur->xmlChildrenNode;
556 while (cur != NULL) {
557 if ((!xmlStrcmp(cur->name, (const xmlChar *)"RECIPE"))) {
558 parseRecipe(doc, cur);
559 }
560 cur = cur->next;
561 }
562 return 0;
563 }
564
565
566
567 /*
568 * Returns:
569 * 0 - All is well, recipes loaded.
570 * 1 - Something went wrong
571 */
572 int rdrecipes(void)
573 {
574 int i;
575 char *mypath;
576 xmlDocPtr doc;
577 xmlNodePtr cur;
578 a_recipe *recipe;
579
580 /*
581 * Search config file
582 */
583 mypath = xstrcpy(etcpath);
584 mypath = xstrcat(mypath, (char *)"recipes.xml");
585
586 /*
587 * Free possible old recipes list
588 */
589 for (recipe = recipes; recipe; recipe = recipe->next) {
590 if (recipe->uuid)
591 free(recipe->uuid);
592 if (recipe->code)
593 free(recipe->code);
594 if (recipe->name)
595 free(recipe->name);
596 for (i = 0; i < 8; i++)
597 if (recipe->mash[i].name)
598 free(recipe->mash[i].name);
599 for (i = 0; i < 10; i++)
600 if (recipe->hops[i].name)
601 free(recipe->hops[i].name);
602 for (i = 0; i < 3; i++)
603 if (recipe->hopstand[i].name)
604 free(recipe->hopstand[i].name);
605 free(recipe);
606 }
607 recipes = NULL;
608
609 /*
610 * See if we have a recipes file.
611 */
612 if (file_exist(mypath, W_OK)) {
613 syslog(LOG_NOTICE, "rdrecipes: %s not found, good.", mypath);
614 free(mypath);
615 return 0;
616 }
617
618 if ((doc = xmlParseFile(mypath)) == NULL) {
619 syslog(LOG_NOTICE, "rdrecipes: %s not found, we may need some.", mypath);
620 free(mypath);
621 return 0;
622 }
623 syslog(LOG_NOTICE, "rdrecipes: using %s", mypath);
624
625 if ((cur = xmlDocGetRootElement(doc)) == NULL) {
626 syslog(LOG_NOTICE, "XML file %s empty.", mypath);
627 xmlFreeDoc(doc);
628 return 1;
629 }
630 if (xmlStrcmp(cur->name, (const xmlChar*)"BREWCO")) {
631 syslog(LOG_NOTICE, "XML file %s is not a valid configuration file.", mypath);
632 xmlFreeDoc(doc);
633 return 1;
634 }
635
636 /*
637 * Parse recipes
638 */
639 cur = cur->xmlChildrenNode;
640 while (cur != NULL) {
641 if ((!xmlStrcmp(cur->name, (const xmlChar *)"RECIPES"))) {
642 parseRecipes(doc, cur);
643 }
644 cur = cur->next;
645 }
646 xmlFreeDoc(doc);
647
648 free(mypath);
649 mypath = NULL;
650
651 return 0;
652 }
653
654
655

mercurial