source: tags/svn.1.5.4/ARBDB/aditem.cxx

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