1 | // =============================================================== // |
---|
2 | // // |
---|
3 | // File : ad_config.cxx // |
---|
4 | // Purpose : editor configurations (aka species selections) // |
---|
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 | |
---|
21 | void 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 = NULp; |
---|
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 | |
---|
59 | GBDATA *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) : NULp; |
---|
63 | } |
---|
64 | |
---|
65 | static GBDATA *findOrCreate_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 | |
---|
79 | GBT_config::GBT_config(GBDATA *gb_main, const char *name, GB_ERROR& error) { |
---|
80 | GB_transaction ta(gb_main); |
---|
81 | GBDATA *gb_config = GBT_find_configuration(gb_main, name); |
---|
82 | |
---|
83 | error = NULp; |
---|
84 | if (!gb_config) { |
---|
85 | error = GBS_global_string("No such configuration '%s'", name); |
---|
86 | top_area = NULp; |
---|
87 | middle_area = NULp; |
---|
88 | comment = NULp; |
---|
89 | } |
---|
90 | else { |
---|
91 | top_area = GBT_read_string(gb_config, "top_area"); |
---|
92 | middle_area = GBT_read_string(gb_config, "middle_area"); |
---|
93 | |
---|
94 | if (!top_area || !middle_area) { |
---|
95 | error = GBS_global_string("Configuration '%s' is corrupted (Reason: %s)", name, GB_await_error()); |
---|
96 | } |
---|
97 | |
---|
98 | comment = GBT_read_string(gb_config, "comment"); |
---|
99 | } |
---|
100 | } |
---|
101 | |
---|
102 | GB_ERROR GBT_config::saveAsOver(GBDATA *gb_main, const char *name, const char *oldName, bool warnIfSavingDefault) const { |
---|
103 | /*! save config as 'name' (overwriting config 'oldName') |
---|
104 | * if 'warnIfSavingDefault' is true, saving DEFAULT_CONFIGURATION raises a warning |
---|
105 | */ |
---|
106 | GB_ERROR error = NULp; |
---|
107 | |
---|
108 | GB_push_transaction(gb_main); |
---|
109 | |
---|
110 | GBDATA *gb_config = findOrCreate_configuration(gb_main, oldName); |
---|
111 | if (!gb_config) { |
---|
112 | error = GBS_global_string("Can't create configuration '%s' (Reason: %s)", oldName, GB_await_error()); |
---|
113 | } |
---|
114 | else { |
---|
115 | if (strcmp(name, oldName) != 0) error = GBT_write_string(gb_config, "name", name); |
---|
116 | |
---|
117 | error = GBT_write_string(gb_config, "top_area", top_area); |
---|
118 | if (!error) error = GBT_write_string(gb_config, "middle_area", middle_area); |
---|
119 | |
---|
120 | if (!error) { |
---|
121 | if (comment && comment[0]) { // non-empty |
---|
122 | error = GBT_write_string(gb_config, "comment", comment); |
---|
123 | } |
---|
124 | else { |
---|
125 | GBDATA *gb_comment = GB_entry(gb_config, "comment"); |
---|
126 | if (gb_comment) error = GB_delete(gb_comment); // delete field if comment empty |
---|
127 | } |
---|
128 | } |
---|
129 | |
---|
130 | if (error) error = GBS_global_string("%s (in configuration '%s')", error, name); |
---|
131 | } |
---|
132 | |
---|
133 | if (warnIfSavingDefault && strcmp(name, DEFAULT_CONFIGURATION) == 0) { |
---|
134 | GBT_message(gb_main, "Note: You saved the '" DEFAULT_CONFIGURATION "'.\nStarting ARB_EDIT4 will probably overwrite it!"); |
---|
135 | } |
---|
136 | |
---|
137 | return GB_end_transaction(gb_main, error); |
---|
138 | } |
---|
139 | |
---|
140 | const GBT_config_item& GBT_config_parser::nextItem(GB_ERROR& error) { |
---|
141 | error = NULp; |
---|
142 | |
---|
143 | freenull(item.name); |
---|
144 | item.type = CI_END_OF_CONFIG; |
---|
145 | |
---|
146 | if (config_string[parse_pos]) { // if not at 0-byte |
---|
147 | char label = config_string[parse_pos+1]; |
---|
148 | item.type = CI_UNKNOWN; |
---|
149 | |
---|
150 | switch (label) { |
---|
151 | case 'L': item.type = CI_SPECIES; break; |
---|
152 | case 'S': item.type = CI_SAI; break; |
---|
153 | case 'F': item.type = CI_FOLDED_GROUP; break; |
---|
154 | case 'G': item.type = CI_GROUP; break; |
---|
155 | case 'E': item.type = CI_CLOSE_GROUP; break; |
---|
156 | default: item.type = CI_UNKNOWN; break; |
---|
157 | } |
---|
158 | |
---|
159 | if (item.type == CI_CLOSE_GROUP) { |
---|
160 | parse_pos += 2; |
---|
161 | } |
---|
162 | else { |
---|
163 | const char *start_of_name = config_string+parse_pos+2; |
---|
164 | const char *behind_name = strchr(start_of_name, '\1'); |
---|
165 | |
---|
166 | if (!behind_name) behind_name = strchr(start_of_name, '\0'); // eos |
---|
167 | gb_assert(behind_name); |
---|
168 | |
---|
169 | char *data = ARB_strpartdup(start_of_name, behind_name-1); |
---|
170 | if (item.type == CI_UNKNOWN) { |
---|
171 | error = GBS_global_string_copy("Unknown flag '%c' (followed by '%s')", label, data); |
---|
172 | free(data); |
---|
173 | } |
---|
174 | else { |
---|
175 | item.name = data; |
---|
176 | parse_pos = behind_name-config_string; |
---|
177 | } |
---|
178 | } |
---|
179 | |
---|
180 | if (error) { // stop parser |
---|
181 | const char *end_of_config = strchr(config_string+parse_pos, '\0'); |
---|
182 | parse_pos = end_of_config-config_string; |
---|
183 | gb_assert(config_string[parse_pos] == 0); |
---|
184 | } |
---|
185 | } |
---|
186 | |
---|
187 | return item; |
---|
188 | } |
---|
189 | |
---|
190 | void GBT_append_to_config_string(const GBT_config_item& item, struct GBS_strstruct *strstruct) { |
---|
191 | // strstruct has to be created by GBS_stropen() |
---|
192 | |
---|
193 | gb_assert((item.type & (CI_UNKNOWN|CI_END_OF_CONFIG)) == 0); |
---|
194 | |
---|
195 | char prefix[] = "\1?"; |
---|
196 | if (item.type == CI_CLOSE_GROUP) { |
---|
197 | prefix[1] = 'E'; |
---|
198 | GBS_strcat(strstruct, prefix); |
---|
199 | } |
---|
200 | else { |
---|
201 | char label = 0; |
---|
202 | switch (item.type) { |
---|
203 | case CI_SPECIES: label = 'L'; break; |
---|
204 | case CI_SAI: label = 'S'; break; |
---|
205 | case CI_GROUP: label = 'G'; break; |
---|
206 | case CI_FOLDED_GROUP: label = 'F'; break; |
---|
207 | |
---|
208 | default: gb_assert(0); break; |
---|
209 | } |
---|
210 | prefix[1] = label; |
---|
211 | GBS_strcat(strstruct, prefix); |
---|
212 | GBS_strcat(strstruct, item.name); |
---|
213 | } |
---|
214 | } |
---|
215 | |
---|
216 | // -------------------------------------------------------------------------------- |
---|
217 | |
---|
218 | #ifdef UNIT_TESTS |
---|
219 | #include <test_unit.h> |
---|
220 | |
---|
221 | void TEST_GBT_get_configuration_names() { |
---|
222 | GB_shell shell; |
---|
223 | GBDATA *gb_main = GB_open("nosuch.arb", "c"); |
---|
224 | |
---|
225 | { |
---|
226 | GB_transaction ta(gb_main); |
---|
227 | |
---|
228 | const char *configs[] = { "arb", "BASIC", "Check it", "dummy" }; |
---|
229 | for (size_t i = 0; i<ARRAY_ELEMS(configs); ++i) { |
---|
230 | TEST_EXPECT_RESULT__NOERROREXPORTED(findOrCreate_configuration(gb_main, configs[i])); |
---|
231 | } |
---|
232 | |
---|
233 | ConstStrArray cnames; |
---|
234 | GBT_get_configuration_names(cnames, gb_main); |
---|
235 | |
---|
236 | TEST_EXPECT_EQUAL(cnames.size(), 4U); |
---|
237 | |
---|
238 | char *joined = GBT_join_strings(cnames, '*'); |
---|
239 | TEST_EXPECT_EQUAL(joined, "arb*BASIC*Check it*dummy"); |
---|
240 | free(joined); |
---|
241 | } |
---|
242 | |
---|
243 | GB_close(gb_main); |
---|
244 | } |
---|
245 | |
---|
246 | #endif // UNIT_TESTS |
---|
247 | |
---|
248 | |
---|