source: tags/arb_5.5/ARBDB/aditem.c

Last change on this file was 6100, checked in by westram, 16 years ago
  • fix warning "format not a string literal and no format arguments"
    • GB_export_error → GB_export_error/GB_export_errorf
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 16.2 KB
Line 
1/* ============================================================ */
2/*                                                              */
3/*   File      : aditem.c                                       */
4/*   Purpose   : item functions                                 */
5/*                                                              */
6/*   Institute of Microbiology (Technical University Munich)    */
7/*   www.arb-home.de                                            */
8/*                                                              */
9/* ============================================================ */
10
11/* items are e.g. species, SAIs, genes, etc */
12
13#include <string.h>
14#include <stdlib.h>
15
16#include <adlocal.h>
17#include <arbdbt.h>
18
19
20GBDATA *GBT_find_or_create_item_rel_item_data(GBDATA *gb_item_data, const char *itemname, const char *id_field, const char *id, GB_BOOL markCreated) {
21    /* Search for a item with field 'id_field' set to given 'id' (id compare is case-insensitive)
22     * If item does not exist, create it.
23     * Newly created items are automatically marked, if 'markCreated' is GB_TRUE
24     * items may be: species, genes, SAIs, ...
25     */
26
27    GBDATA   *gb_item = 0;
28    GB_ERROR  error   = 0;
29
30    if (!gb_item_data) error = "No container";
31    else {
32        gb_item = GBT_find_item_rel_item_data(gb_item_data, id_field, id);
33        if (!gb_item) {
34            error = GB_push_transaction(gb_item_data);
35            if (!error) {
36                gb_item             = GB_create_container(gb_item_data, itemname); // create a new item
37                if (!gb_item) error = GB_await_error();
38                else {
39                    error = GBT_write_string(gb_item, id_field, id); // write item identifier
40                    if (!error && markCreated) error = GB_write_flag(gb_item, 1); // mark generated item
41                }
42            }
43            error = GB_end_transaction(gb_item_data, error);
44        }
45    }
46
47    if (!gb_item && !error) error = GB_await_error();
48    if (error) {
49        gb_item = 0;
50        GB_export_errorf("Can't create %s '%s': %s", itemname, id, error);
51    }
52
53    return gb_item;
54}
55
56GBDATA *GBT_find_or_create_species_rel_species_data(GBDATA *gb_species_data, const char *name) {
57    return GBT_find_or_create_item_rel_item_data(gb_species_data, "species", "name", name, GB_TRUE);
58}
59
60GBDATA *GBT_find_or_create_species(GBDATA *gb_main, const char *name) {
61    return GBT_find_or_create_species_rel_species_data(GBT_get_species_data(gb_main), name);
62}
63
64GBDATA *GBT_find_or_create_SAI(GBDATA *gb_main,const char *name) {
65    /* Search for an SAI, when SAI does not exist, create it */
66    return GBT_find_or_create_item_rel_item_data(GBT_get_SAI_data(gb_main), "extended", "name", name, GB_TRUE);
67}
68
69
70/********************************************************************************************
71                    some simple find procedures
72********************************************************************************************/
73
74GBDATA *GBT_find_item_rel_item_data(GBDATA *gb_item_data, const char *id_field, const char *id_value) {
75    // 'gb_item_data' is a container containing items
76    // 'id_field' is a field containing a unique identifier for each item (e.g. 'name' for species)
77    //
78    // returns a pointer to an item with 'id_field' containing 'id_value'
79    // or NULL (in this case an error MAY be exported)
80    //
81    // Note: If you expect the item to exist, use GBT_expect_item_rel_item_data!
82
83    GBDATA *gb_item_id = GB_find_string(gb_item_data, id_field, id_value, GB_IGNORE_CASE, down_2_level);
84    return gb_item_id ? GB_get_father(gb_item_id) : 0;
85}
86
87GBDATA *GBT_expect_item_rel_item_data(GBDATA *gb_item_data, const char *id_field, const char *id_value) {
88    // like GBT_find_item_rel_item_data, but also exports an error if the item is not present
89
90    GBDATA *gb_found = GBT_find_item_rel_item_data(gb_item_data, id_field, id_value);
91    if (!gb_found && !GB_have_error()) { // item simply not exists
92        GBDATA     *gb_any   = GB_find(gb_item_data, id_field, down_2_level);
93        const char *itemname = gb_any ? GB_read_key_pntr(GB_get_father(gb_any)) : "<item>";
94        GB_export_errorf("Could not find %s with %s '%s'", itemname, id_field, id_value);
95    }
96    return gb_found;
97}
98
99/* -------------------------------------------------------------------------------- */
100
101GBDATA *GBT_get_species_data(GBDATA *gb_main) {
102    return GB_search(gb_main,"species_data",GB_CREATE_CONTAINER);
103}
104
105GBDATA *GBT_first_marked_species_rel_species_data(GBDATA *gb_species_data) {
106    return GB_first_marked(gb_species_data,"species");
107}
108
109GBDATA *GBT_first_marked_species(GBDATA *gb_main) {
110    return GB_first_marked(GBT_get_species_data(gb_main), "species");
111}
112GBDATA *GBT_next_marked_species(GBDATA *gb_species) {
113    gb_assert(GB_has_key(gb_species, "species"));
114    return GB_next_marked(gb_species,"species");
115}
116
117GBDATA *GBT_first_species_rel_species_data(GBDATA *gb_species_data) {
118    return GB_entry(gb_species_data,"species");
119}
120GBDATA *GBT_first_species(GBDATA *gb_main) {
121    return GB_entry(GBT_get_species_data(gb_main),"species");
122}
123
124GBDATA *GBT_next_species(GBDATA *gb_species) {
125    gb_assert(GB_has_key(gb_species, "species"));
126    return GB_nextEntry(gb_species);
127}
128
129GBDATA *GBT_find_species_rel_species_data(GBDATA *gb_species_data,const char *name) {
130    return GBT_find_item_rel_item_data(gb_species_data, "name", name);
131}
132GBDATA *GBT_find_species(GBDATA *gb_main, const char *name) {
133    // Search for a species.
134    // Return found species or NULL (in this case an error MAY be exported).
135    //
136    // Note: If you expect the species to exists, use GBT_expect_species!
137    return GBT_find_item_rel_item_data(GBT_get_species_data(gb_main), "name", name);
138}
139
140GBDATA *GBT_expect_species(GBDATA *gb_main, const char *name) {
141    // Returns an existing species or
142    // NULL (in that case an error is exported)
143    return GBT_expect_item_rel_item_data(GBT_get_species_data(gb_main), "name", name);
144}
145
146/* -------------------------------------------------------------------------------- */
147
148GBDATA *GBT_get_SAI_data(GBDATA *gb_main) {
149    return GB_search(gb_main, "extended_data", GB_CREATE_CONTAINER);
150}
151
152GBDATA *GBT_first_marked_SAI_rel_SAI_data(GBDATA *gb_sai_data) {
153    return GB_first_marked(gb_sai_data, "extended");
154}
155
156GBDATA *GBT_next_marked_SAI(GBDATA *gb_sai) {
157    gb_assert(GB_has_key(gb_sai, "extended"));
158    return GB_next_marked(gb_sai, "extended");
159}
160
161/* Search SAIs */
162GBDATA *GBT_first_SAI_rel_SAI_data(GBDATA *gb_sai_data) {
163    return GB_entry(gb_sai_data, "extended");
164}
165GBDATA *GBT_first_SAI(GBDATA *gb_main) {
166    return GB_entry(GBT_get_SAI_data(gb_main),"extended");
167}
168
169GBDATA *GBT_next_SAI(GBDATA *gb_sai) {
170    gb_assert(GB_has_key(gb_sai, "extended"));
171    return GB_nextEntry(gb_sai);
172}
173
174GBDATA *GBT_find_SAI_rel_SAI_data(GBDATA *gb_sai_data, const char *name) {
175    return GBT_find_item_rel_item_data(gb_sai_data, "name", name);
176}
177GBDATA *GBT_find_SAI(GBDATA *gb_main, const char *name) {
178    // Search for a SAI.
179    // Return found SAI or NULL (in this case an error MAY be exported).
180    //
181    // Note: If you expect the SAI to exist, use GBT_expect_SAI!
182    return GBT_find_item_rel_item_data(GBT_get_SAI_data(gb_main), "name", name);
183}
184
185GBDATA *GBT_expect_SAI(GBDATA *gb_main, const char *name) {
186    // Returns an existing SAI or
187    // NULL (in that case an error is exported)
188    return GBT_expect_item_rel_item_data(GBT_get_SAI_data(gb_main), "name", name);
189}
190
191/* --------------------- */
192/*      count items      */
193
194long GBT_get_item_count(GBDATA *gb_parent_of_container, const char *item_container_name) {
195    // returns elements stored in a container
196
197    GBDATA *gb_item_data;
198    long    count = 0;
199
200    GB_push_transaction(gb_parent_of_container);
201    gb_item_data = GB_entry(gb_parent_of_container, item_container_name);
202    if (gb_item_data) count = GB_number_of_subentries(gb_item_data);
203    GB_pop_transaction(gb_parent_of_container);
204
205    return count;
206}
207
208long GBT_get_species_count(GBDATA *gb_main) {
209    return GBT_get_item_count(gb_main, "species_data");
210}
211
212long GBT_get_SAI_count(GBDATA *gb_main) {
213    return GBT_get_item_count(gb_main, "extended_data");
214}
215
216/* -------------------------------------------------------------------------------- */
217
218char *GBT_create_unique_item_identifier(GBDATA *gb_item_container, const char *id_field, const char *default_id) {
219    // returns an identifier not used by items in 'gb_item_container'
220    // 'id_field' is the entry that is used as identifier (e.g. 'name' for species)
221    // 'default_id' will be suffixed with a number to generate a unique id
222    //
223    // Note:
224    // * The resulting id may be longer than 8 characters
225    // * This function is slow, so just use in extra-ordinary situations
226
227    GBDATA *gb_item   = GBT_find_item_rel_item_data(gb_item_container, id_field, default_id);
228    char   *unique_id;
229
230    if (!gb_item) {
231        unique_id = strdup(default_id); // default_id is unused
232    }
233    else {
234        char   *generated_id  = malloc(strlen(default_id)+20);
235        size_t  min_num = 1;
236
237#define GENERATE_ID(num) sprintf(generated_id,"%s%zi", default_id, num);
238       
239        GENERATE_ID(min_num);
240        gb_item = GBT_find_item_rel_item_data(gb_item_container, id_field, generated_id);
241
242        if (gb_item) {
243            size_t num_items = GB_number_of_subentries(gb_item_container);
244            size_t max_num   = 0;
245
246            ad_assert(num_items); // otherwise deadlock below
247
248            do {
249                max_num += num_items;
250                GENERATE_ID(max_num);
251                gb_item  = GBT_find_item_rel_item_data(gb_item_container, id_field, generated_id);
252            } while (gb_item && max_num >= num_items);
253
254            if (max_num<num_items) { // overflow
255                char *uid;
256                generated_id[0] = 'a'+GB_random(26);
257                generated_id[1] = 'a'+GB_random(26);
258                generated_id[2] = 0;
259
260                uid = GBT_create_unique_item_identifier(gb_item_container, id_field, generated_id);
261                strcpy(generated_id, uid);
262                free(uid);
263            }
264            else {
265                // max_num is unused
266                while ((max_num-min_num)>1) {
267                    size_t mid = (min_num+max_num)/2;
268                    ad_assert(mid != min_num && mid != max_num);
269
270                    GENERATE_ID(mid);
271                    gb_item = GBT_find_item_rel_item_data(gb_item_container, id_field, generated_id);
272
273                    if (gb_item) min_num = mid;
274                    else max_num = mid;
275                }
276                GENERATE_ID(max_num);
277                ad_assert(GBT_find_item_rel_item_data(gb_item_container, id_field, generated_id) == NULL);
278            }
279        }
280        unique_id = generated_id;
281
282#undef GENERATE_ID
283    }
284
285    return unique_id;
286}
287
288char *GBT_create_unique_species_name(GBDATA *gb_main, const char *default_name) {
289    return GBT_create_unique_item_identifier(GBT_get_species_data(gb_main), "name", default_name);
290}
291
292
293/********************************************************************************************
294                    mark and unmark species
295********************************************************************************************/
296void GBT_mark_all(GBDATA *gb_main, int flag)
297{
298    GBDATA *gb_species;
299    GB_push_transaction(gb_main);
300
301    if (flag == 2) {
302        for (gb_species = GBT_first_species(gb_main);
303             gb_species;
304             gb_species = GBT_next_species(gb_species) )
305        {
306            GB_write_flag(gb_species,!GB_read_flag(gb_species));
307        }
308    }
309    else {
310        gb_assert(flag == 0 || flag == 1);
311
312        for (gb_species = GBT_first_species(gb_main);
313             gb_species;
314             gb_species = GBT_next_species(gb_species) )
315        {
316            GB_write_flag(gb_species,flag);
317        }
318    }
319    GB_pop_transaction(gb_main);
320}
321void GBT_mark_all_that(GBDATA *gb_main, int flag, int (*condition)(GBDATA*, void*), void *cd)
322{
323    GBDATA *gb_species;
324    GB_push_transaction(gb_main);
325
326    if (flag == 2) {
327        for (gb_species = GBT_first_species(gb_main);
328             gb_species;
329             gb_species = GBT_next_species(gb_species) )
330        {
331            if (condition(gb_species, cd)) {
332                GB_write_flag(gb_species,!GB_read_flag(gb_species));
333            }
334        }
335    }
336    else {
337        gb_assert(flag == 0 || flag == 1);
338
339        for (gb_species = GBT_first_species(gb_main);
340             gb_species;
341             gb_species = GBT_next_species(gb_species) )
342        {
343            int curr_flag = GB_read_flag(gb_species);
344            if (curr_flag != flag && condition(gb_species, cd)) {
345                GB_write_flag(gb_species,flag);
346            }
347        }
348    }
349    GB_pop_transaction(gb_main);
350}
351
352long GBT_count_marked_species(GBDATA *gb_main)
353{
354    long    cnt = 0;
355    GBDATA *gb_species_data;
356
357    GB_push_transaction(gb_main);
358    gb_species_data = GB_search(gb_main,"species_data",GB_CREATE_CONTAINER);
359    GB_pop_transaction(gb_main);
360
361    cnt = GB_number_of_marked_subentries(gb_species_data);
362    return cnt;
363}
364
365char *GBT_store_marked_species(GBDATA *gb_main, int unmark_all)
366{
367    /* stores the currently marked species in a string
368       if (unmark_all != 0) then unmark them too
369    */
370
371    void   *out = GBS_stropen(10000);
372    GBDATA *gb_species;
373
374    for (gb_species = GBT_first_marked_species(gb_main);
375         gb_species;
376         gb_species = GBT_next_marked_species(gb_species))
377    {
378        GBS_strcat(out, GBT_read_name(gb_species));
379        GBS_chrcat(out, ';');
380        if (unmark_all) GB_write_flag(gb_species, 0);
381    }
382
383    GBS_str_cut_tail(out, 1); // remove trailing ';'
384    return GBS_strclose(out);
385}
386
387NOT4PERL GB_ERROR GBT_with_stored_species(GBDATA *gb_main, const char *stored, species_callback doit, int *clientdata) {
388    /* call function 'doit' with all species stored in 'stored' */
389
390#define MAX_NAME_LEN 20
391    char     name[MAX_NAME_LEN+1];
392    GB_ERROR error = 0;
393
394    while (!error) {
395        char   *p   = strchr(stored, ';');
396        int     len = p ? (p-stored) : (int)strlen(stored);
397        GBDATA *gb_species;
398
399        gb_assert(len <= MAX_NAME_LEN);
400        memcpy(name, stored, len);
401        name[len] = 0;
402
403        gb_species = GBT_find_species(gb_main, name);
404        if (gb_species) {
405            error = doit(gb_species, clientdata);
406        }
407        else {
408            error = "Some stored species where not found.";
409        }
410
411        if (!p) break;
412        stored = p+1;
413    }
414#undef MAX_NAME_LEN
415    return error;
416}
417
418static GB_ERROR restore_mark(GBDATA *gb_species, int *clientdata) {
419    GBUSE(clientdata);
420    GB_write_flag(gb_species, 1);
421    return 0;
422}
423
424GB_ERROR GBT_restore_marked_species(GBDATA *gb_main, const char *stored_marked) {
425    /* restores the species-marks to a state currently saved
426       into 'stored_marked' by GBT_store_marked_species
427    */
428
429    GBT_mark_all(gb_main, 0);   /* unmark all species */
430    return GBT_with_stored_species(gb_main, stored_marked, restore_mark, 0);
431}
432
433/********************************************************************************************
434                    read species information
435********************************************************************************************/
436
437#if defined(DEVEL_RALF)
438#warning rename the following functions to make the difference more obvious??
439#endif /* DEVEL_RALF */
440GB_CSTR GBT_read_name(GBDATA *gb_item) {
441    GB_CSTR result      = GBT_read_char_pntr(gb_item, "name");
442    if (!result) result = GBS_global_string("<unnamed_%s>", GB_read_key_pntr(gb_item));
443    return result;
444}
445
446const char *GBT_get_name(GBDATA *gb_item) {
447    GBDATA *gb_name = GB_entry(gb_item, "name");
448    if (!gb_name) return 0;
449    return GB_read_char_pntr(gb_name);
450}
451
452GBDATA **GBT_gen_species_array(GBDATA *gb_main, long *pspeccnt)
453{
454    GBDATA *gb_species;
455    GBDATA *gb_species_data = GBT_find_or_create(gb_main,"species_data",7);
456    GBDATA **result;
457    *pspeccnt = 0;
458    for (gb_species = GBT_first_species_rel_species_data(gb_species_data);
459         gb_species;
460         gb_species = GBT_next_species(gb_species)){
461        (*pspeccnt) ++;
462    }
463    result = (GBDATA **)malloc((size_t)(sizeof(GBDATA *)* (*pspeccnt)));
464    *pspeccnt = 0;
465    for (gb_species = GBT_first_species_rel_species_data(gb_species_data);
466         gb_species;
467         gb_species = GBT_next_species(gb_species)){
468        result[(*pspeccnt)++]=gb_species;
469    }
470    return result;
471}
472
Note: See TracBrowser for help on using the repository browser.