source: branches/profile/ARBDB/ad_config.cxx

Last change on this file was 11165, checked in by westram, 10 years ago
  • stuffed leak in "rename species"
  • Note: atm all unittests pass with valgrind activated
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 11.5 KB
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : ad_config.cxx                                     //
4//   Purpose   : editor configurations                             //
5//                                                                 //
6//   Coded by Ralf Westram (coder@reallysoft.de) in May 2005       //
7//   Institute of Microbiology (Technical University Munich)       //
8//   http://www.arb-home.de/                                       //
9//                                                                 //
10// =============================================================== //
11
12#include "gb_local.h"
13
14#include <ad_config.h>
15#include <arbdbt.h>
16
17#include <arb_strbuf.h>
18#include <arb_defs.h>
19#include <arb_strarray.h>
20
21void GBT_get_configuration_names(ConstStrArray& configNames, GBDATA *gb_main) {
22    /* returns existing configurations in 'configNames'
23     * Note: automatically generates names for configs w/o legal name.
24     */
25
26    GB_transaction  ta(gb_main);
27    GBDATA         *gb_config_data = GB_search(gb_main, CONFIG_DATA_PATH, GB_CREATE_CONTAINER);
28
29    if (gb_config_data) {
30        int unnamed_count = 0;
31
32        configNames.reserve(GB_number_of_subentries(gb_config_data));
33       
34        for (GBDATA *gb_config = GB_entry(gb_config_data, CONFIG_ITEM);
35             gb_config;
36             gb_config = GB_nextEntry(gb_config))
37        {
38            const char *name = GBT_read_char_pntr(gb_config, "name");
39
40            if (!name || name[0] == 0) { // no name or empty name
41                char     *new_name = GBS_global_string_copy("<unnamed%i>", ++unnamed_count);
42                GB_ERROR  error    = GBT_write_string(gb_config, "name", new_name);
43
44                if (error) {
45                    GB_warningf("Failed to rename unnamed configuration to '%s'", new_name);
46                    freenull(new_name);
47                    name = NULL;
48                }
49                else {
50                    name = GBT_read_char_pntr(gb_config, "name");
51                }
52            }
53
54            if (name) configNames.put(name);
55        }
56    }
57}
58
59GBDATA *GBT_find_configuration(GBDATA *gb_main, const char *name) {
60    GBDATA *gb_config_data = GB_search(gb_main, CONFIG_DATA_PATH, GB_DB);
61    GBDATA *gb_config_name = GB_find_string(gb_config_data, "name", name, GB_IGNORE_CASE, SEARCH_GRANDCHILD);
62    return gb_config_name ? GB_get_father(gb_config_name) : 0;
63}
64
65GBDATA *GBT_create_configuration(GBDATA *gb_main, const char *name) {
66    GBDATA *gb_config = GBT_find_configuration(gb_main, name);
67    if (!gb_config) {
68        GBDATA *gb_config_data = GB_search(gb_main, CONFIG_DATA_PATH, GB_DB);
69
70        gb_config = GB_create_container(gb_config_data, CONFIG_ITEM); // create new container
71        if (gb_config) {
72            GB_ERROR error = GBT_write_string(gb_config, "name", name);
73            if (error) GB_export_error(error);
74        }
75    }
76    return gb_config;
77}
78
79void GBT_free_configuration_data(GBT_config *data) {
80    free(data->top_area);
81    free(data->middle_area);
82    free(data);
83}
84
85GBT_config *GBT_load_configuration_data(GBDATA *gb_main, const char *name, GB_ERROR *error) {
86    GBT_config *config = 0;
87
88    *error            = GB_push_transaction(gb_main);
89    GBDATA *gb_config = GBT_find_configuration(gb_main, name);
90
91    if (!gb_config) {
92        *error = GBS_global_string("No such configuration '%s'", name);
93    }
94    else {
95        config              = (GBT_config*)GB_calloc(1, sizeof(*config));
96        config->top_area    = GBT_read_string(gb_config, "top_area");
97        config->middle_area = GBT_read_string(gb_config, "middle_area");
98
99        if (!config->top_area || !config->middle_area) {
100            GBT_free_configuration_data(config);
101            config = 0;
102            *error = GBS_global_string("Configuration '%s' is corrupted (Reason: %s)",
103                                       name, GB_await_error());
104        }
105    }
106
107    *error = GB_end_transaction(gb_main, *error);
108    return config;
109}
110
111GB_ERROR GBT_save_configuration_data(GBT_config *config, GBDATA *gb_main, const char *name) {
112    GB_ERROR  error = 0;
113    GBDATA   *gb_config;
114
115    GB_push_transaction(gb_main);
116
117    gb_config = GBT_create_configuration(gb_main, name);
118    if (!gb_config) {
119        error = GBS_global_string("Can't create configuration '%s' (Reason: %s)", name, GB_await_error());
120    }
121    else {
122        error             = GBT_write_string(gb_config, "top_area", config->top_area);
123        if (!error) error = GBT_write_string(gb_config, "middle_area", config->middle_area);
124
125        if (error) error = GBS_global_string("%s (in configuration '%s')", error, name);
126    }
127
128    return GB_end_transaction(gb_main, error);
129}
130
131GBT_config_parser *GBT_start_config_parser(const char *config_string) {
132    GBT_config_parser *parser = (GBT_config_parser*)GB_calloc(1, sizeof(*parser));
133
134    parser->config_string = nulldup(config_string);
135    parser->parse_pos     = 0;
136
137    return parser;
138}
139
140GBT_config_item *GBT_create_config_item() {
141    GBT_config_item *item = (GBT_config_item*)GB_calloc(1, sizeof(*item));
142    item->type            = CI_UNKNOWN;
143    item->name            = 0;
144    return item;
145}
146
147void GBT_free_config_item(GBT_config_item *item) {
148    free(item->name);
149    free(item);
150}
151
152GB_ERROR GBT_parse_next_config_item(GBT_config_parser *parser, GBT_config_item *item) {
153    // the passed 'item' gets filled with parsed data from the config string
154    GB_ERROR error = 0;
155
156    const char *str = parser->config_string;
157    int         pos = parser->parse_pos;
158
159    freenull(item->name);
160    item->type = CI_END_OF_CONFIG;
161
162    if (str[pos]) {             // if not at 0-byte
163        char label = str[pos+1];
164        item->type = CI_UNKNOWN;
165
166        switch (label) {
167            case 'L': item->type = CI_SPECIES; break;
168            case 'S': item->type = CI_SAI; break;
169            case 'F': item->type = CI_FOLDED_GROUP; break;
170            case 'G': item->type = CI_GROUP; break;
171            case 'E': item->type = CI_CLOSE_GROUP; break;
172            default: item->type = CI_UNKNOWN; break;
173        }
174
175        if (item->type == CI_CLOSE_GROUP) {
176            pos += 2;
177        }
178        else {
179            const char *start_of_name = str+pos+2;
180            const char *behind_name   = strchr(start_of_name, '\1');
181
182            if (!behind_name) behind_name = strchr(start_of_name, '\0'); // eos
183            gb_assert(behind_name);
184
185            char *data = GB_strpartdup(start_of_name, behind_name-1);
186            if (item->type == CI_UNKNOWN) {
187                error = GBS_global_string_copy("Unknown flag '%c' (followed by '%s')", label, data);
188                free(data);
189            }
190            else {
191                item->name = data;
192                pos        = behind_name-str;
193            }
194        }
195
196        if (error) { // stop parser
197            const char *end_of_config = strchr(str+pos, '\0');
198            pos                 = end_of_config-str;
199            gb_assert(str[pos] == 0);
200        }
201
202        parser->parse_pos = pos;
203    }
204    return error;
205}
206
207void GBT_append_to_config_string(const GBT_config_item *item, GBS_strstruct *strstruct) {
208    // strstruct has to be created by GBS_stropen()
209
210    gb_assert((item->type & (CI_UNKNOWN|CI_END_OF_CONFIG)) == 0);
211
212    char prefix[] = "\1?";
213    if (item->type == CI_CLOSE_GROUP) {
214        prefix[1] = 'E';
215        GBS_strcat(strstruct, prefix);
216    }
217    else {
218        char label = 0;
219        switch (item->type) {
220            case CI_SPECIES:      label = 'L'; break;
221            case CI_SAI:          label = 'S'; break;
222            case CI_GROUP:        label = 'G'; break;
223            case CI_FOLDED_GROUP: label = 'F'; break;
224
225            default: gb_assert(0); break;
226        }
227        prefix[1] = label;
228        GBS_strcat(strstruct, prefix);
229        GBS_strcat(strstruct, item->name);
230    }
231}
232
233
234void GBT_free_config_parser(GBT_config_parser *parser) {
235    free(parser->config_string);
236    free(parser);
237}
238
239#if defined(DEBUG)
240void GBT_test_config_parser(GBDATA *gb_main) {
241    ConstStrArray config_names;
242    GBT_get_configuration_names(config_names, gb_main);
243    if (!config_names.empty()) {
244        int count;
245        for (count = 0; config_names[count]; ++count) {
246            const char *config_name = config_names[count];
247            GBT_config *config;
248            GB_ERROR    error       = 0;
249
250            printf("Testing configuration '%s':\n", config_name);
251            config = GBT_load_configuration_data(gb_main, config_name, &error);
252            if (!config) {
253                gb_assert(error);
254                printf("* Error loading config: %s\n", error);
255            }
256            else {
257                int area;
258
259                gb_assert(!error);
260                printf("* Successfully loaded\n");
261
262                for (area = 0; area<2 && !error; ++area) {
263                    const char        *area_name       = area ? "middle_area" : "top_area";
264                    const char        *area_config_def = area ? config->middle_area : config->top_area;
265                    GBT_config_parser *parser          = GBT_start_config_parser(area_config_def);
266                    GBT_config_item   *item            = GBT_create_config_item();
267                    GBS_strstruct     *new_config      = GBS_stropen(1000);
268                    char              *new_config_str;
269
270                    gb_assert(parser);
271                    printf("* Created parser for '%s'\n", area_name);
272
273                    while (1) {
274                        error = GBT_parse_next_config_item(parser, item);
275                        if (error || item->type == CI_END_OF_CONFIG) break;
276
277                        printf("  - %i %s\n", item->type, item->name ? item->name : "[close group]");
278                        GBT_append_to_config_string(item, new_config);
279                    }
280
281                    GBT_free_config_item(item);
282                    new_config_str = GBS_strclose(new_config);
283
284                    if (error) printf("* Parser error: %s\n", error);
285                    else {
286                        if (strcmp(area_config_def, new_config_str) == 0) {
287                            printf("* Re-Created config is identical to original\n");
288                        }
289                        else {
290                            printf("* Re-Created config is NOT identical to original:\n"
291                                   "  - original : '%s'\n"
292                                   "  - recreated: '%s'\n",
293                                   area_config_def,
294                                   new_config_str);
295                        }
296                    }
297
298                    GBT_free_config_parser(parser);
299                    free(new_config_str);
300                }
301            }
302            GBT_free_configuration_data(config);
303        }
304    }
305}
306#endif // DEBUG
307
308// --------------------------------------------------------------------------------
309
310#ifdef UNIT_TESTS
311#include <test_unit.h>
312
313void TEST_GBT_get_configuration_names() {
314    GB_shell  shell;
315    GBDATA   *gb_main = GB_open("nosuch.arb", "c");
316
317    {
318        GB_transaction ta(gb_main);
319
320        const char *configs[] = { "arb", "BASIC", "Check it", "dummy" };
321        for (size_t i = 0; i<ARRAY_ELEMS(configs); ++i) {
322            TEST_EXPECT_RESULT__NOERROREXPORTED(GBT_create_configuration(gb_main, configs[i]));
323        }
324
325        ConstStrArray cnames;
326        GBT_get_configuration_names(cnames, gb_main);
327
328        TEST_EXPECT_EQUAL(cnames.size(), 4U);
329
330        char *joined = GBT_join_names(cnames, '*');
331        TEST_EXPECT_EQUAL(joined, "arb*BASIC*Check it*dummy");
332        free(joined);
333    }
334
335    GB_close(gb_main);
336}
337
338#endif // UNIT_TESTS
Note: See TracBrowser for help on using the repository browser.