ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/common/recipe.C
Revision: 1.14
Committed: Wed Jan 3 02:30:51 2007 UTC (17 years, 4 months ago) by elmex
Content type: text/plain
Branch: MAIN
Changes since 1.13: +1 -1 lines
Log Message:
implemented proper support for empty treasures, which
sadly occur in empty treasure lists. fixing treasurelists
to have no entries at all would be even more complicated,
but even when this is fixed, the current changes only make the
server more crash robust to bad treasures.
Also removed the 'NONE' specialcase for treasure lists. Developers
should use 'none' instead now.

File Contents

# User Rev Content
1 elmex 1.1 /* Basic stuff for use with the alchemy code. Clearly some of this stuff
2     * could go into server/alchemy, but I left it here just in case it proves
3     * more generally useful.
4     *
5     * Nov 1995 - file created by b.t. thomas@astro.psu.edu
6     */
7    
8    
9     /* Our definition of 'formula' is any product of an alchemical process.
10     * Ingredients are just comma delimited list of archetype (or object)
11     * names.
12     */
13    
14     /* Example 'formula' entry in libdir/formulae:
15     * Object transparency
16     * chance 10
17     * ingred dust of beholdereye,gem
18     * arch potion_generic
19     */
20    
21 root 1.11 #include <cctype>
22    
23 elmex 1.1 #include <global.h>
24     #include <object.h>
25    
26 root 1.5 static void build_stringlist (const char *str, char ***result_list, size_t * result_size);
27 elmex 1.1
28     static recipelist *formulalist;
29    
30 root 1.5 static recipelist *
31     init_recipelist (void)
32     {
33 root 1.3 recipelist *tl = new recipelist;
34    
35 root 1.5 tl->total_chance = 0;
36     tl->number = 0;
37     tl->items = NULL;
38     tl->next = NULL;
39 elmex 1.1 return tl;
40     }
41    
42 root 1.5 static recipe *
43     get_empty_formula (void)
44     {
45 root 1.3 recipe *t = new recipe;
46    
47 elmex 1.1 t->chance = 0;
48     t->index = 0;
49     t->transmute = 0;
50 root 1.5 t->yield = 0;
51     t->diff = 0;
52     t->exp = 0;
53 elmex 1.1 t->keycode = 0;
54     t->title = NULL;
55     t->arch_names = 0;
56     t->arch_name = NULL;
57     t->skill = NULL;
58     t->cauldron = NULL;
59     t->ingred = NULL;
60 root 1.5 t->next = NULL;
61 elmex 1.1 return t;
62     }
63 root 1.5
64 elmex 1.1 /* get_formulalist() - returns pointer to the formula list */
65    
66 root 1.5 recipelist *
67     get_formulalist (int i)
68     {
69     recipelist *fl = formulalist;
70     int number = i;
71    
72     while (fl && number > 1)
73     {
74     if (!(fl = fl->next))
75     break;
76     number--;
77     }
78 elmex 1.1 return fl;
79     }
80    
81     /* check_recipe() - makes sure we actually have the requested artifact
82     * and archetype. */
83    
84 root 1.5 static int
85     check_recipe (const recipe *rp)
86     {
87     size_t i;
88     int result;
89    
90     result = 1;
91     for (i = 0; i < rp->arch_names; i++)
92     {
93 root 1.6 if (archetype::find (rp->arch_name[i]) != NULL)
94 root 1.5 {
95     artifact *art = locate_recipe_artifact (rp, i);
96    
97     if (!art && strcmp (rp->title, "NONE") != 0)
98     {
99 pippijn 1.12 LOG (llevError, "WARNING: Formula %s of %s has no artifact.\n", rp->arch_name[i], &rp->title);
100 root 1.5 result = 0;
101 elmex 1.1 }
102 root 1.5 }
103     else
104     {
105 pippijn 1.12 LOG (llevError, "WARNING: Can't find archetype %s for formula %s\n", rp->arch_name[i], &rp->title);
106 root 1.5 result = 0;
107 elmex 1.1 }
108     }
109 root 1.5
110     return result;
111 elmex 1.1 }
112    
113    
114     /*
115     * init_formulae() - Builds up the lists of formula from the file in
116     * the libdir. -b.t.
117     */
118 root 1.5
119     void
120     init_formulae (void)
121     {
122     static int has_been_done = 0;
123 elmex 1.1 FILE *fp;
124     char filename[MAX_BUF], buf[MAX_BUF], *cp, *next;
125 root 1.5 recipe *formula = NULL;
126     recipelist *fl = init_recipelist ();
127 elmex 1.1 linked_char *tmp;
128     int value, comp;
129    
130 root 1.5 if (!formulalist)
131     formulalist = fl;
132    
133     if (has_been_done)
134 elmex 1.1 return;
135 root 1.5 else
136     has_been_done = 1;
137    
138     sprintf (filename, "%s/formulae", settings.datadir);
139 pippijn 1.12 LOG (llevDebug, "Reading alchemical formulae from %s...\n", filename);
140 root 1.5 if ((fp = open_and_uncompress (filename, 0, &comp)) == NULL)
141     {
142     LOG (llevError, "Can't open %s.\n", filename);
143     return;
144     }
145    
146     while (fgets (buf, MAX_BUF, fp) != NULL)
147     {
148     if (*buf == '#')
149     continue;
150     if ((cp = strchr (buf, '\n')) != NULL)
151     *cp = '\0';
152     cp = buf;
153     while (*cp == ' ') /* Skip blanks */
154     cp++;
155    
156     if (!strncmp (cp, "Object", 6))
157     {
158     formula = get_empty_formula ();
159     formula->title = strchr (cp, ' ') + 1;
160     }
161     else if (!strncmp (cp, "keycode", 7))
162     {
163     formula->keycode = strchr (cp, ' ') + 1;
164     }
165     else if (sscanf (cp, "trans %d", &value))
166     {
167     formula->transmute = (uint16) value;
168     }
169     else if (sscanf (cp, "yield %d", &value))
170     {
171     formula->yield = (uint16) value;
172     }
173     else if (sscanf (cp, "chance %d", &value))
174     {
175     formula->chance = (uint16) value;
176     }
177     else if (sscanf (cp, "exp %d", &value))
178     {
179     formula->exp = (uint16) value;
180     }
181     else if (sscanf (cp, "diff %d", &value))
182     {
183     formula->diff = (uint16) value;
184     }
185     else if (!strncmp (cp, "ingred", 6))
186     {
187     int numb_ingred = 1;
188    
189     cp = strchr (cp, ' ') + 1;
190     do
191     {
192     if ((next = strchr (cp, ',')) != NULL)
193     {
194     *(next++) = '\0';
195     numb_ingred++;
196     }
197     tmp = new linked_char;
198    
199     tmp->name = cp;
200     tmp->next = formula->ingred;
201     formula->ingred = tmp;
202     /* each ingredient's ASCII value is coadded. Later on this
203     * value will be used allow us to search the formula lists
204     * quickly for the right recipe.
205     */
206     formula->index += strtoint (cp);
207     }
208     while ((cp = next) != NULL);
209     /* now find the correct (# of ingred ordered) formulalist */
210     fl = formulalist;
211     while (numb_ingred != 1)
212     {
213     if (!fl->next)
214     fl->next = init_recipelist ();
215     fl = fl->next;
216     numb_ingred--;
217     }
218     fl->total_chance += formula->chance;
219     fl->number++;
220     formula->next = fl->items;
221     fl->items = formula;
222     }
223     else if (!strncmp (cp, "arch", 4))
224     {
225     build_stringlist (strchr (cp, ' ') + 1, &formula->arch_name, &formula->arch_names);
226     check_recipe (formula);
227     }
228     else if (!strncmp (cp, "skill", 5))
229     {
230     formula->skill = strchr (cp, ' ') + 1;
231     }
232     else if (!strncmp (cp, "cauldron", 8))
233     {
234     formula->cauldron = strchr (cp, ' ') + 1;
235     }
236     else
237     LOG (llevError, "Unknown input in file %s: %s\n", filename, buf);
238     }
239     LOG (llevDebug, "done.\n");
240     close_and_delete (fp, comp);
241 elmex 1.1 /* Lastly, lets check for problems in formula we got */
242 root 1.5 check_formulae ();
243 elmex 1.1 }
244    
245     /* check_formulae()- since we are doing a squential search on the
246     * formulae lists now, we have to be carefull that we dont have 2
247     * formula with the exact same index value. Under the new nbatches
248     * code, it is possible to have multiples of ingredients in a cauldron
249     * which could result in an index formula mismatch. We *don't* check for
250     * that possibility here. -b.t.
251     */
252 root 1.5 void
253     check_formulae (void)
254     {
255 elmex 1.1 recipelist *fl;
256     recipe *check, *formula;
257     int numb = 1;
258    
259 pippijn 1.13 LOG (llevDebug, "Checking formulae lists...\n");
260 elmex 1.1
261 root 1.5 for (fl = formulalist; fl != NULL; fl = fl->next)
262     {
263     for (formula = fl->items; formula != NULL; formula = formula->next)
264     for (check = formula->next; check != NULL; check = check->next)
265     if (check->index == formula->index)
266     {
267     LOG (llevError, " ERROR: On %d ingred list: ", numb);
268     LOG (llevError, "Formulae [%s] of %s and [%s] of %s have matching index id (%d)\n",
269     formula->arch_name[0], &formula->title, check->arch_name[0], &check->title, formula->index);
270     }
271     numb++;
272     }
273 elmex 1.1
274 root 1.5 LOG (llevDebug, "done.\n");
275 elmex 1.1
276     }
277    
278     /* Borrowed (again) from the artifacts code for this */
279    
280 root 1.5 void
281     dump_alchemy (void)
282     {
283     recipelist *fl = formulalist;
284     recipe *formula = NULL;
285 elmex 1.1 linked_char *next;
286 root 1.5 int num_ingred = 1;
287 elmex 1.1
288 root 1.5 fprintf (logfile, "\n");
289     while (fl)
290     {
291     fprintf (logfile, "\n Formulae with %d ingredient%s %d Formulae with total_chance=%d\n",
292     num_ingred, num_ingred > 1 ? "s." : ".", fl->number, fl->total_chance);
293     for (formula = fl->items; formula != NULL; formula = formula->next)
294     {
295     artifact *art = NULL;
296     char buf[MAX_BUF];
297     size_t i;
298    
299     for (i = 0; i < formula->arch_names; i++)
300     {
301     const char *string = formula->arch_name[i];
302    
303 root 1.6 if (archetype::find (string) != NULL)
304 root 1.5 {
305     art = locate_recipe_artifact (formula, i);
306     if (!art && strcmp (formula->title, "NONE"))
307     LOG (llevError, "Formula %s has no artifact\n", &formula->title);
308     else
309     {
310     if (strcmp (formula->title, "NONE"))
311     sprintf (buf, "%s of %s", string, &formula->title);
312     else
313     sprintf (buf, "%s", string);
314     fprintf (logfile, "%-30s(%d) bookchance %3d ", buf, formula->index, formula->chance);
315     fprintf (logfile, "skill %s", &formula->skill);
316     fprintf (logfile, "\n");
317     if (formula->ingred != NULL)
318     {
319     int nval = 0, tval = 0;
320    
321     fprintf (logfile, "\tIngred: ");
322     for (next = formula->ingred; next != NULL; next = next->next)
323     {
324     if (nval != 0)
325     fprintf (logfile, ",");
326     fprintf (logfile, "%s(%d)", &next->name, (nval = strtoint (next->name)));
327     tval += nval;
328     }
329     fprintf (logfile, "\n");
330     if (tval != formula->index)
331     fprintf (logfile, "WARNING:ingredient list and formula values not equal.\n");
332     }
333     if (formula->skill != NULL)
334     fprintf (logfile, "\tSkill Required: %s", &formula->skill);
335     if (formula->cauldron != NULL)
336     fprintf (logfile, "\tCauldron: %s\n", &formula->cauldron);
337     fprintf (logfile, "\tDifficulty: %d\t Exp: %d\n", formula->diff, formula->exp);
338     }
339 root 1.2 }
340 root 1.5 else
341     LOG (llevError, "Can't find archetype:%s for formula %s\n", string, &formula->title);
342     }
343     }
344     fprintf (logfile, "\n");
345     fl = fl->next;
346     num_ingred++;
347     }
348 elmex 1.1 }
349    
350     /* Find a treasure with a matching name. The 'depth' parameter is
351     * only there to prevent infinite loops in treasure lists (a list
352     * referencing another list pointing back to the first one). */
353 root 1.5 archetype *
354     find_treasure_by_name (const treasure *t, const char *name, int depth)
355 elmex 1.1 {
356     treasurelist *tl;
357 root 1.5 archetype *at;
358 elmex 1.1
359     if (depth > 10)
360 elmex 1.10 return 0;
361    
362     while (t)
363 elmex 1.1 {
364 elmex 1.10 if (t->name)
365 root 1.2 {
366     tl = find_treasurelist (t->name);
367 elmex 1.10
368     if (tl)
369     {
370     at = find_treasure_by_name (tl->items, name, depth + 1);
371    
372     if (at)
373     return at;
374     }
375 root 1.2 }
376 elmex 1.1 else
377 root 1.2 {
378 elmex 1.14 if (t->item && !strcasecmp (t->item->clone.name, name))
379 root 1.2 return t->item;
380     }
381 elmex 1.10
382     if (t->next_yes)
383 root 1.2 {
384     at = find_treasure_by_name (t->next_yes, name, depth);
385 elmex 1.10 if (at)
386 root 1.2 return at;
387     }
388 elmex 1.10
389     if (t->next_no)
390 root 1.2 {
391     at = find_treasure_by_name (t->next_no, name, depth);
392 elmex 1.10 if (at)
393 root 1.2 return at;
394     }
395 elmex 1.1 t = t->next;
396     }
397 elmex 1.10 return 0;
398 elmex 1.1 }
399    
400     /* If several archetypes have the same name, the value of the first
401     * one with that name will be returned. This happens for the
402     * mushrooms (mushroom_1, mushroom_2 and mushroom_3). For the
403     * monsters' body parts, there may be several monsters with the same
404     * name. This is not a problem if these monsters have the same level
405     * (e.g. sage & c_sage) or if only one of the monsters generates the
406     * body parts that we are looking for (e.g. big_dragon and
407     * big_dragon_worthless). */
408 root 1.5 long
409     find_ingred_cost (const char *name)
410 elmex 1.1 {
411 root 1.5 archetype *at;
412     archetype *at2;
413 elmex 1.1 artifactlist *al;
414 root 1.5 artifact *art;
415     long mult;
416     char *cp;
417     char part1[100];
418     char part2[100];
419 elmex 1.1
420     /* same as atoi(), but skip number */
421     mult = 0;
422     while (isdigit (*name))
423     {
424     mult = 10 * mult + (*name - '0');
425     name++;
426     }
427     if (mult > 0)
428     name++;
429     else
430     mult = 1;
431     /* first, try to match the name of an archetype */
432 root 1.5 for (at = first_archetype; at != NULL; at = at->next)
433 elmex 1.1 {
434     if (at->clone.title != NULL)
435 root 1.2 {
436     /* inefficient, but who cares? */
437 root 1.3 sprintf (part1, "%s %s", &at->clone.name, &at->clone.title);
438 root 1.5 if (!strcasecmp (part1, name))
439 root 1.2 return mult * at->clone.value;
440     }
441 root 1.5 if (!strcasecmp (at->clone.name, name))
442 root 1.2 return mult * at->clone.value;
443 elmex 1.1 }
444     /* second, try to match an artifact ("arch of something") */
445     cp = strstr (name, " of ");
446     if (cp != NULL)
447     {
448     strcpy (part1, name);
449     part1[cp - name] = '\0';
450     strcpy (part2, cp + 4);
451     /* find the first archetype matching the first part of the name */
452 root 1.5 for (at = first_archetype; at != NULL; at = at->next)
453     if (!strcasecmp (at->clone.name, part1) && at->clone.title == NULL)
454 root 1.2 break;
455 elmex 1.1 if (at != NULL)
456 root 1.2 {
457     /* find the first artifact derived from that archetype (same type) */
458     for (al = first_artifactlist; al != NULL; al = al->next)
459     if (al->type == at->clone.type)
460     {
461     for (art = al->items; art != NULL; art = art->next)
462 root 1.5 if (!strcasecmp (art->item->name, part2))
463 root 1.2 return mult * at->clone.value * art->item->value;
464     }
465     }
466 elmex 1.1 }
467     /* third, try to match a body part ("arch's something") */
468     cp = strstr (name, "'s ");
469     if (cp != NULL)
470     {
471     strcpy (part1, name);
472     part1[cp - name] = '\0';
473     strcpy (part2, cp + 3);
474     /* examine all archetypes matching the first part of the name */
475 root 1.5 for (at = first_archetype; at != NULL; at = at->next)
476     if (!strcasecmp (at->clone.name, part1) && at->clone.title == NULL)
477 root 1.2 {
478     if (at->clone.randomitems != NULL)
479     {
480 root 1.5 at2 = find_treasure_by_name (at->clone.randomitems->items, part2, 0);
481 elmex 1.10 if (at2)
482 root 1.2 return mult * at2->clone.value * isqrt (at->clone.level * 2);
483     }
484     }
485 elmex 1.1 }
486     /* failed to find any matching items -- formula should be checked */
487     return -1;
488     }
489    
490     /* code copied from dump_alchemy() and modified by Raphael Quinet */
491 root 1.5 void
492     dump_alchemy_costs (void)
493 elmex 1.1 {
494 root 1.5 recipelist *fl = formulalist;
495     recipe *formula = NULL;
496 elmex 1.1 linked_char *next;
497 root 1.5 int num_ingred = 1;
498     int num_errors = 0;
499 elmex 1.1 long cost;
500     long tcost;
501    
502     fprintf (logfile, "\n");
503 root 1.5 while (fl)
504     {
505     fprintf (logfile, "\n Formulae with %d ingredient%s %d Formulae with total_chance=%d\n",
506     num_ingred, num_ingred > 1 ? "s." : ".", fl->number, fl->total_chance);
507     for (formula = fl->items; formula != NULL; formula = formula->next)
508     {
509     artifact *art = NULL;
510     archetype *at = NULL;
511     char buf[MAX_BUF];
512     size_t i;
513    
514     for (i = 0; i < formula->arch_names; i++)
515 root 1.2 {
516 root 1.5 const char *string = formula->arch_name[i];
517    
518 root 1.6 if ((at = archetype::find (string)) != NULL)
519 root 1.2 {
520 root 1.5 art = locate_recipe_artifact (formula, i);
521     if (!art && strcmp (formula->title, "NONE"))
522     LOG (llevError, "Formula %s has no artifact\n", &formula->title);
523 root 1.2 else
524     {
525 root 1.5 if (!strcmp (formula->title, "NONE"))
526     sprintf (buf, "%s", string);
527     else
528     sprintf (buf, "%s of %s", string, &formula->title);
529     fprintf (logfile, "\n%-40s bookchance %3d skill %s\n", buf, formula->chance, &(formula->skill));
530     if (formula->ingred != NULL)
531     {
532     tcost = 0;
533     for (next = formula->ingred; next != NULL; next = next->next)
534     {
535     cost = find_ingred_cost (next->name);
536     if (cost < 0)
537     num_errors++;
538     fprintf (logfile, "\t%-33s%5ld\n", &next->name, cost);
539     if (cost < 0 || tcost < 0)
540     tcost = -1;
541     else
542     tcost += cost;
543     }
544     if (art != NULL && art->item != NULL)
545     cost = at->clone.value * art->item->value;
546     else
547     cost = at->clone.value;
548     fprintf (logfile, "\t\tBuying result costs: %5ld", cost);
549     if (formula->yield > 1)
550     {
551     fprintf (logfile, " to %ld (max %d items)\n", cost * formula->yield, formula->yield);
552     cost = cost * (formula->yield + 1L) / 2L;
553     }
554     else
555     fprintf (logfile, "\n");
556     fprintf (logfile, "\t\tIngredients cost: %5ld\n\t\tComment: ", tcost);
557     if (tcost < 0)
558     fprintf (logfile, "Could not find some ingredients. Check the formula!\n");
559     else if (tcost > cost)
560     fprintf (logfile, "Ingredients are much too expensive. Useless formula.\n");
561     else if (tcost * 2L > cost)
562     fprintf (logfile, "Ingredients are too expensive.\n");
563     else if (tcost * 10L < cost)
564     fprintf (logfile, "Ingredients are too cheap.\n");
565     else
566     fprintf (logfile, "OK.\n");
567     }
568 root 1.2 }
569     }
570 root 1.5 else
571     LOG (llevError, "Can't find archetype:%s for formula %s\n", string, &formula->title);
572 root 1.2 }
573     }
574 root 1.5 fprintf (logfile, "\n");
575     fl = fl->next;
576     num_ingred++;
577     }
578 elmex 1.1 if (num_errors > 0)
579 root 1.5 fprintf (logfile, "WARNING: %d objects required by the formulae do not exist in the game.\n", num_errors);
580 elmex 1.1 }
581    
582 root 1.5 const char *
583     ingred_name (const char *name)
584     {
585     const char *cp = name;
586    
587     if (atoi (cp))
588     cp = strchr (cp, ' ') + 1;
589 elmex 1.1 return cp;
590     }
591    
592     /* strtoint() - we use this to convert buf into an integer
593     * equal to the coadded sum of the (lowercase) character
594     * ASCII values in buf (times prepended integers).
595     */
596    
597 root 1.5 int
598     strtoint (const char *buf)
599     {
600     const char *cp = ingred_name (buf);
601     int val = 0, len = strlen (cp), mult = numb_ingred (buf);
602 elmex 1.1
603 root 1.5 while (len)
604     {
605     val += tolower (*cp);
606     cp++;
607     len--;
608     }
609     return val * mult;
610 elmex 1.1 }
611    
612 root 1.5 artifact *
613     locate_recipe_artifact (const recipe *rp, size_t idx)
614     {
615     object *item = get_archetype (rp->arch_name[idx]);
616     artifactlist *at = NULL;
617     artifact *art = NULL;
618    
619     if (!item)
620     return (artifact *) NULL;
621 elmex 1.1
622 root 1.5 if ((at = find_artifactlist (item->type)))
623     for (art = at->items; art; art = art->next)
624     if (!strcmp (art->item->name, rp->title))
625     break;
626 elmex 1.1
627 root 1.9 item->destroy ();
628 elmex 1.1
629 root 1.5 return art;
630 elmex 1.1 }
631    
632 root 1.5 int
633     numb_ingred (const char *buf)
634     {
635 elmex 1.1 int numb;
636    
637 root 1.5 if ((numb = atoi (buf)))
638     return numb;
639     else
640     return 1;
641     }
642    
643     recipelist *
644     get_random_recipelist (void)
645     {
646     recipelist *fl = NULL;
647     int number = 0, roll = 0;
648    
649     /* first, determine # of recipelist we have */
650     for (fl = get_formulalist (1); fl; fl = fl->next)
651     number++;
652    
653     /* now, randomly choose one */
654     if (number > 0)
655     roll = RANDOM () % number;
656    
657     fl = get_formulalist (1);
658     while (roll && fl)
659     {
660     if (fl->next)
661     fl = fl->next;
662     else
663     break;
664     roll--;
665     }
666     if (!fl) /* failed! */
667     LOG (llevError, "get_random_recipelist(): no recipelists found!\n");
668     else if (fl->total_chance == 0)
669     fl = get_random_recipelist ();
670    
671     return fl;
672 elmex 1.1 }
673    
674 root 1.5 recipe *
675     get_random_recipe (recipelist * rpl)
676     {
677     recipelist *fl = rpl;
678     recipe *rp = NULL;
679     int r = 0;
680    
681     /* looks like we have to choose a random one */
682     if (fl == NULL)
683     if ((fl = get_random_recipelist ()) == NULL)
684     return rp;
685    
686     if (fl->total_chance > 0)
687     {
688     r = RANDOM () % fl->total_chance;
689     for (rp = fl->items; rp; rp = rp->next)
690     {
691     r -= rp->chance;
692     if (r < 0)
693     break;
694     }
695 elmex 1.1 }
696     return rp;
697     }
698    
699 root 1.5 void
700     free_all_recipes (void)
701 elmex 1.1 {
702 root 1.5 recipelist *fl = formulalist, *flnext;
703     recipe *formula = NULL, *next;
704     linked_char *lchar, *charnext;
705    
706     LOG (llevDebug, "Freeing all the recipes\n");
707     for (fl = formulalist; fl != NULL; fl = flnext)
708     {
709     flnext = fl->next;
710    
711     for (formula = fl->items; formula != NULL; formula = next)
712     {
713     next = formula->next;
714    
715     free (formula->arch_name[0]);
716     free (formula->arch_name);
717    
718     for (lchar = formula->ingred; lchar; lchar = charnext)
719     {
720     charnext = lchar->next;
721     delete lchar;
722 root 1.2 }
723 root 1.5 delete formula;
724 root 1.2 }
725 root 1.3
726 root 1.5 delete fl;
727 elmex 1.1 }
728     }
729    
730     /**
731     * Split a comma separated string list into words.
732     *
733     * @param str the string to split
734     *
735     * @param result_list pointer to return value for the newly created list; the
736     * caller is responsible for freeing both *result_list and **result_list.
737     *
738     * @param result_size pointer to return value for the size of the newly
739     * created list
740     */
741 root 1.5 static void
742     build_stringlist (const char *str, char ***result_list, size_t * result_size)
743 elmex 1.1 {
744 root 1.5 char *dup;
745     char *p;
746     size_t size;
747     size_t i;
748 elmex 1.1
749 root 1.11 dup = strdup (str);
750 root 1.5 if (dup == NULL)
751     fatal (OUT_OF_MEMORY);
752 elmex 1.1
753 root 1.5 size = 0;
754     for (p = strtok (dup, ","); p != NULL; p = strtok (NULL, ","))
755     size++;
756 elmex 1.1
757 root 1.5 *result_list = (char **) malloc (size * sizeof (*result_list));
758 root 1.3
759 root 1.5 *result_size = size;
760 elmex 1.1
761 root 1.5 for (i = 0; i < size; i++)
762     {
763     (*result_list)[i] = dup;
764     dup = dup + strlen (dup) + 1;
765 elmex 1.1 }
766     }