1 | // =============================================================== // |
---|
2 | // // |
---|
3 | // File : adquery.cxx // |
---|
4 | // Purpose : // |
---|
5 | // // |
---|
6 | // Institute of Microbiology (Technical University Munich) // |
---|
7 | // http://www.arb-home.de/ // |
---|
8 | // // |
---|
9 | // =============================================================== // |
---|
10 | |
---|
11 | #include "gb_aci.h" |
---|
12 | #include "gb_comm.h" |
---|
13 | #include "gb_index.h" |
---|
14 | #include "gb_key.h" |
---|
15 | #include "gb_localdata.h" |
---|
16 | #include "gb_ta.h" |
---|
17 | |
---|
18 | #include <arb_strbuf.h> |
---|
19 | |
---|
20 | #include <cctype> |
---|
21 | |
---|
22 | #define GB_PATH_MAX 1024 |
---|
23 | |
---|
24 | static void build_GBDATA_path(GBDATA *gbd, char **buffer) { |
---|
25 | GBCONTAINER *gbc = GB_FATHER(gbd); |
---|
26 | const char *key; |
---|
27 | |
---|
28 | if (gbc) { |
---|
29 | build_GBDATA_path((GBDATA*)gbc, buffer); |
---|
30 | key = GB_KEY(gbd); |
---|
31 | { |
---|
32 | char *bp = *buffer; |
---|
33 | *bp++ = '/'; |
---|
34 | while (*key) *bp++ = *key++; |
---|
35 | *bp = 0; |
---|
36 | |
---|
37 | *buffer = bp; |
---|
38 | } |
---|
39 | } |
---|
40 | } |
---|
41 | |
---|
42 | #define BUFFERSIZE 1024 |
---|
43 | |
---|
44 | static const char *GB_get_GBDATA_path(GBDATA *gbd) { |
---|
45 | static char *orgbuffer = NULL; |
---|
46 | char *buffer; |
---|
47 | |
---|
48 | if (!orgbuffer) orgbuffer = (char*)malloc(BUFFERSIZE); |
---|
49 | buffer = orgbuffer; |
---|
50 | |
---|
51 | build_GBDATA_path(gbd, &buffer); |
---|
52 | assert_or_exit((buffer-orgbuffer) < BUFFERSIZE); // buffer overflow |
---|
53 | |
---|
54 | return orgbuffer; |
---|
55 | } |
---|
56 | |
---|
57 | // ---------------- |
---|
58 | // QUERIES |
---|
59 | |
---|
60 | static bool gb_find_value_equal(GBDATA *gb, GB_TYPES type, const char *val, GB_CASE case_sens) { |
---|
61 | bool equal = false; |
---|
62 | |
---|
63 | #if defined(DEBUG) |
---|
64 | GB_TYPES realtype = GB_TYPE(gb); |
---|
65 | gb_assert(val); |
---|
66 | if (type == GB_STRING) { |
---|
67 | gb_assert(realtype == GB_STRING || realtype == GB_LINK); // gb_find_internal called with wrong type |
---|
68 | } |
---|
69 | else { |
---|
70 | gb_assert(realtype == type); // gb_find_internal called with wrong type |
---|
71 | } |
---|
72 | #endif // DEBUG |
---|
73 | |
---|
74 | switch (type) { |
---|
75 | case GB_STRING: |
---|
76 | case GB_LINK: |
---|
77 | equal = GBS_string_matches(GB_read_char_pntr(gb), val, case_sens); |
---|
78 | break; |
---|
79 | |
---|
80 | case GB_INT: { |
---|
81 | int i = GB_read_int(gb); |
---|
82 | if (i == *(int*)val) equal = true; |
---|
83 | break; |
---|
84 | } |
---|
85 | case GB_FLOAT: { |
---|
86 | double d = GB_read_float(gb); |
---|
87 | if (d == *(double*)val) equal = true; // (no aliasing problem here; char* -> double* ok) |
---|
88 | break; |
---|
89 | } |
---|
90 | default: { |
---|
91 | const char *err = GBS_global_string("Value search not supported for data type %i (%i)", GB_TYPE(gb), type); |
---|
92 | GB_internal_error(err); |
---|
93 | break; |
---|
94 | } |
---|
95 | } |
---|
96 | |
---|
97 | return equal; |
---|
98 | } |
---|
99 | |
---|
100 | static GBDATA *find_sub_by_quark(GBDATA *father, GBQUARK key_quark, GB_TYPES type, const char *val, GB_CASE case_sens, GBDATA *after, size_t skip_over) { |
---|
101 | /* search an entry with a key 'key_quark' below a container 'father' |
---|
102 | after position 'after' |
---|
103 | |
---|
104 | if 'skip_over' > 0 search skips 'skip_over' entries |
---|
105 | |
---|
106 | if (val != NULL) search for entry with value 'val': |
---|
107 | |
---|
108 | GB_STRING/GB_LINK: compares string (case_sensitive or not) |
---|
109 | GB_INT: compares values |
---|
110 | GB_FLOAT: ditto (val MUST be a 'double*') |
---|
111 | others: not implemented yet |
---|
112 | |
---|
113 | Note: to search for non-char*-values use GB_find_int() |
---|
114 | for other types write a new similar function |
---|
115 | |
---|
116 | if key_quark<0 search everything |
---|
117 | */ |
---|
118 | |
---|
119 | int end, index; |
---|
120 | GBCONTAINER *gbf = (GBCONTAINER*)father; |
---|
121 | gb_header_list *header; |
---|
122 | GBDATA *gb; |
---|
123 | |
---|
124 | end = gbf->d.nheader; |
---|
125 | header = GB_DATA_LIST_HEADER(gbf->d); |
---|
126 | if (after) index = (int)after->index+1; else index = 0; |
---|
127 | |
---|
128 | if (key_quark<0) { // unspecific key quark (i.e. search all) |
---|
129 | gb_assert(!val); // search for val not possible if searching all keys! |
---|
130 | if (!val) { |
---|
131 | for (; index < end; index++) { |
---|
132 | if (header[index].flags.key_quark != 0) { |
---|
133 | if (header[index].flags.changed >= GB_DELETED) continue; |
---|
134 | if (!(gb=GB_HEADER_LIST_GBD(header[index]))) { |
---|
135 | gb_unfold(gbf, 0, index); |
---|
136 | header = GB_DATA_LIST_HEADER(gbf->d); |
---|
137 | gb = GB_HEADER_LIST_GBD(header[index]); |
---|
138 | if (!gb) { |
---|
139 | const char *err = GBS_global_string("Database entry #%u is missing (in '%s')", index, GB_get_GBDATA_path(father)); |
---|
140 | GB_internal_error(err); |
---|
141 | continue; |
---|
142 | } |
---|
143 | } |
---|
144 | if (!skip_over--) return gb; |
---|
145 | } |
---|
146 | } |
---|
147 | } |
---|
148 | } |
---|
149 | else { // specific key quark |
---|
150 | for (; index < end; index++) { |
---|
151 | if ((key_quark == header[index].flags.key_quark)) { |
---|
152 | if (header[index].flags.changed >= GB_DELETED) continue; |
---|
153 | if (!(gb=GB_HEADER_LIST_GBD(header[index]))) |
---|
154 | { |
---|
155 | gb_unfold(gbf, 0, index); |
---|
156 | header = GB_DATA_LIST_HEADER(gbf->d); |
---|
157 | gb = GB_HEADER_LIST_GBD(header[index]); |
---|
158 | if (!gb) { |
---|
159 | const char *err = GBS_global_string("Database entry #%u is missing (in '%s')", index, GB_get_GBDATA_path(father)); |
---|
160 | GB_internal_error(err); |
---|
161 | continue; |
---|
162 | } |
---|
163 | } |
---|
164 | if (val) { |
---|
165 | if (!gb) { |
---|
166 | GB_internal_error("Cannot unfold data"); |
---|
167 | continue; |
---|
168 | } |
---|
169 | else { |
---|
170 | if (!gb_find_value_equal(gb, type, val, case_sens)) continue; |
---|
171 | } |
---|
172 | } |
---|
173 | if (!skip_over--) return gb; |
---|
174 | } |
---|
175 | } |
---|
176 | } |
---|
177 | return NULL; |
---|
178 | } |
---|
179 | |
---|
180 | GBDATA *GB_find_sub_by_quark(GBDATA *father, GBQUARK key_quark, GBDATA *after, size_t skip_over) { |
---|
181 | return find_sub_by_quark(father, key_quark, GB_NONE, NULL, GB_MIND_CASE, after, skip_over); |
---|
182 | } |
---|
183 | |
---|
184 | static GBDATA *GB_find_subcontent_by_quark(GBDATA *father, GBQUARK key_quark, GB_TYPES type, const char *val, GB_CASE case_sens, GBDATA *after, size_t skip_over) { |
---|
185 | return find_sub_by_quark(father, key_quark, type, val, case_sens, after, skip_over); |
---|
186 | } |
---|
187 | |
---|
188 | static GBDATA *find_sub_sub_by_quark(GBDATA *father, const char *key, GBQUARK sub_key_quark, GB_TYPES type, const char *val, GB_CASE case_sens, GBDATA *after) { |
---|
189 | int end, index; |
---|
190 | gb_header_list *header; |
---|
191 | GBCONTAINER *gbf = (GBCONTAINER*)father; |
---|
192 | GBDATA *gb; |
---|
193 | GBDATA *res; |
---|
194 | gb_index_files *ifs = NULL; |
---|
195 | GB_MAIN_TYPE *Main = GBCONTAINER_MAIN(gbf); |
---|
196 | |
---|
197 | end = gbf->d.nheader; |
---|
198 | header = GB_DATA_LIST_HEADER(gbf->d); |
---|
199 | |
---|
200 | if (after) index = (int)after->index+1; else index = 0; |
---|
201 | |
---|
202 | // ****** look for any hash index tables ******** |
---|
203 | // ****** no wildcards allowed ******* |
---|
204 | if (!Main->local_mode) { |
---|
205 | if (gbf->flags2.folded_container) { |
---|
206 | // do the query in the server |
---|
207 | if (GB_ARRAY_FLAGS(gbf).changed) { |
---|
208 | if (!gbf->flags2.update_in_server) { |
---|
209 | GB_update_server((GBDATA *)gbf); |
---|
210 | } |
---|
211 | } |
---|
212 | } |
---|
213 | if (gbf->d.size > GB_MAX_LOCAL_SEARCH && val) { |
---|
214 | if (after) res = GBCMC_find(after, key, type, val, case_sens, SEARCH_CHILD_OF_NEXT); |
---|
215 | else res = GBCMC_find(father, key, type, val, case_sens, SEARCH_GRANDCHILD); |
---|
216 | return res; |
---|
217 | } |
---|
218 | } |
---|
219 | if (val && |
---|
220 | (ifs=GBCONTAINER_IFS(gbf))!=NULL && |
---|
221 | (!strchr(val, '*')) && |
---|
222 | (!strchr(val, '?'))) |
---|
223 | { |
---|
224 | for (; ifs; ifs = GB_INDEX_FILES_NEXT(ifs)) { |
---|
225 | if (ifs->key != sub_key_quark) continue; |
---|
226 | // ***** We found the index table ***** |
---|
227 | res = gb_index_find(gbf, ifs, sub_key_quark, val, case_sens, index); |
---|
228 | return res; |
---|
229 | } |
---|
230 | } |
---|
231 | |
---|
232 | if (after) gb = after; |
---|
233 | else gb = NULL; |
---|
234 | |
---|
235 | for (; index < end; index++) { |
---|
236 | GBDATA *gbn = GB_HEADER_LIST_GBD(header[index]); |
---|
237 | |
---|
238 | if (header[index].flags.changed >= GB_DELETED) continue; |
---|
239 | if (!gbn) { |
---|
240 | if (!Main->local_mode) { |
---|
241 | if (gb) res = GBCMC_find(gb, key, type, val, case_sens, SEARCH_CHILD_OF_NEXT); |
---|
242 | else res = GBCMC_find(father, key, type, val, case_sens, SEARCH_GRANDCHILD); |
---|
243 | return res; |
---|
244 | } |
---|
245 | GB_internal_error("Empty item in server"); |
---|
246 | continue; |
---|
247 | } |
---|
248 | gb = gbn; |
---|
249 | if (GB_TYPE(gb) != GB_DB) continue; |
---|
250 | res = GB_find_subcontent_by_quark(gb, sub_key_quark, type, val, case_sens, NULL, 0); |
---|
251 | if (res) return res; |
---|
252 | } |
---|
253 | return NULL; |
---|
254 | } |
---|
255 | |
---|
256 | |
---|
257 | static GBDATA *gb_find_internal(GBDATA *gbd, const char *key, GB_TYPES type, const char *val, GB_CASE case_sens, GB_SEARCH_TYPE gbs) { |
---|
258 | GBDATA *result = NULL; |
---|
259 | |
---|
260 | if (gbd) { |
---|
261 | GBDATA *after = NULL; |
---|
262 | GBCONTAINER *gbc = NULL; |
---|
263 | |
---|
264 | switch (gbs) { |
---|
265 | case SEARCH_NEXT_BROTHER: |
---|
266 | after = gbd; |
---|
267 | case SEARCH_BROTHER: |
---|
268 | gbs = SEARCH_CHILD; |
---|
269 | gbc = GB_FATHER(gbd); |
---|
270 | break; |
---|
271 | |
---|
272 | case SEARCH_CHILD: |
---|
273 | case SEARCH_GRANDCHILD: |
---|
274 | if (GB_TYPE(gbd) == GB_DB) gbc = (GBCONTAINER*)gbd; |
---|
275 | break; |
---|
276 | |
---|
277 | case SEARCH_CHILD_OF_NEXT: |
---|
278 | after = gbd; |
---|
279 | gbs = SEARCH_GRANDCHILD; |
---|
280 | gbc = GB_FATHER(gbd); |
---|
281 | break; |
---|
282 | } |
---|
283 | |
---|
284 | if (gbc) { |
---|
285 | GBQUARK key_quark = key ? GB_key_2_quark(gbd, key) : -1; |
---|
286 | |
---|
287 | if (gbs == SEARCH_CHILD) { |
---|
288 | result = GB_find_subcontent_by_quark((GBDATA*)gbc, key_quark, type, val, case_sens, after, 0); |
---|
289 | } |
---|
290 | else { |
---|
291 | gb_assert(gbs == SEARCH_GRANDCHILD); |
---|
292 | result = find_sub_sub_by_quark((GBDATA*)gbc, key, key_quark, type, val, case_sens, after); |
---|
293 | } |
---|
294 | } |
---|
295 | } |
---|
296 | return result; |
---|
297 | } |
---|
298 | |
---|
299 | GBDATA *GB_find(GBDATA *gbd, const char *key, GB_SEARCH_TYPE gbs) { |
---|
300 | // normally you should not need to use GB_find! |
---|
301 | // better use one of the replacement functions |
---|
302 | // (GB_find_string, GB_find_int, GB_child, GB_nextChild, GB_entry, GB_nextEntry, GB_brother) |
---|
303 | return gb_find_internal(gbd, key, GB_NONE, NULL, GB_CASE_UNDEFINED, gbs); |
---|
304 | } |
---|
305 | |
---|
306 | GBDATA *GB_find_string(GBDATA *gbd, const char *key, const char *str, GB_CASE case_sens, GB_SEARCH_TYPE gbs) { |
---|
307 | // search for a subentry of 'gbd' that has |
---|
308 | // - fieldname 'key' |
---|
309 | // - type GB_STRING and |
---|
310 | // - content matching 'str' |
---|
311 | // if 'case_sensitive' is true, content is matched case sensitive. |
---|
312 | // GBS_string_matches is used to compare (supports wildcards) |
---|
313 | return gb_find_internal(gbd, key, GB_STRING, str, case_sens, gbs); |
---|
314 | } |
---|
315 | NOT4PERL GBDATA *GB_find_int(GBDATA *gbd, const char *key, long val, GB_SEARCH_TYPE gbs) { |
---|
316 | // search for a subentry of 'gbd' that has |
---|
317 | // - fieldname 'key' |
---|
318 | // - type GB_INT |
---|
319 | // - and value 'val' |
---|
320 | return gb_find_internal(gbd, key, GB_INT, (const char *)&val, GB_CASE_UNDEFINED, gbs); |
---|
321 | } |
---|
322 | |
---|
323 | // ---------------------------------------------------- |
---|
324 | // iterate over ALL subentries of a container |
---|
325 | |
---|
326 | GBDATA *GB_child(GBDATA *father) { |
---|
327 | // return first child (or NULL if no children) |
---|
328 | return GB_find(father, NULL, SEARCH_CHILD); |
---|
329 | } |
---|
330 | GBDATA *GB_nextChild(GBDATA *child) { |
---|
331 | // return next child after 'child' (or NULL if no more children) |
---|
332 | return GB_find(child, NULL, SEARCH_NEXT_BROTHER); |
---|
333 | } |
---|
334 | |
---|
335 | // ------------------------------------------------------------------------------ |
---|
336 | // iterate over all subentries of a container that have a specified key |
---|
337 | |
---|
338 | GBDATA *GB_entry(GBDATA *father, const char *key) { |
---|
339 | // return first child of 'father' that has fieldname 'key' |
---|
340 | // (or NULL if none found) |
---|
341 | return GB_find(father, key, SEARCH_CHILD); |
---|
342 | } |
---|
343 | GBDATA *GB_nextEntry(GBDATA *entry) { |
---|
344 | // return next child after 'entry', that has the same fieldname |
---|
345 | // (or NULL if 'entry' is last one) |
---|
346 | return GB_find_sub_by_quark((GBDATA*)GB_FATHER(entry), GB_get_quark(entry), entry, 0); |
---|
347 | } |
---|
348 | GBDATA *GB_followingEntry(GBDATA *entry, size_t skip_over) { |
---|
349 | // return following child after 'entry', that has the same fieldname |
---|
350 | // (or NULL if no such entry) |
---|
351 | // skips 'skip_over' entries (skip_over == 0 behaves like GB_nextEntry) |
---|
352 | return GB_find_sub_by_quark((GBDATA*)GB_FATHER(entry), GB_get_quark(entry), entry, skip_over); |
---|
353 | } |
---|
354 | |
---|
355 | GBDATA *GB_brother(GBDATA *entry, const char *key) { |
---|
356 | // searches (first) brother (before or after) of 'entry' which has field 'key' |
---|
357 | // i.e. does same as GB_entry(GB_get_father(entry), key) |
---|
358 | return GB_find(entry, key, SEARCH_BROTHER); |
---|
359 | } |
---|
360 | |
---|
361 | GBDATA *gb_find_by_nr(GBDATA *father, int index) { |
---|
362 | /* get a subentry by its internal number: |
---|
363 | Warning: This subentry must exists, otherwise internal error */ |
---|
364 | |
---|
365 | GBCONTAINER *gbf = (GBCONTAINER*)father; |
---|
366 | gb_header_list *header; |
---|
367 | GBDATA *gb; |
---|
368 | |
---|
369 | if (GB_TYPE(father) != GB_DB) { |
---|
370 | GB_internal_error("type is not GB_DB"); |
---|
371 | return NULL; |
---|
372 | } |
---|
373 | header = GB_DATA_LIST_HEADER(gbf->d); |
---|
374 | if (index >= gbf->d.nheader || index <0) { |
---|
375 | GB_internal_errorf("Index '%i' out of range [%i:%i[", index, 0, gbf->d.nheader); |
---|
376 | return NULL; |
---|
377 | } |
---|
378 | if (header[index].flags.changed >= GB_DELETED || !header[index].flags.key_quark) { |
---|
379 | GB_internal_error("Entry already deleted"); |
---|
380 | return NULL; |
---|
381 | } |
---|
382 | if (!(gb=GB_HEADER_LIST_GBD(header[index]))) |
---|
383 | { |
---|
384 | gb_unfold(gbf, 0, index); |
---|
385 | header = GB_DATA_LIST_HEADER(gbf->d); |
---|
386 | gb = GB_HEADER_LIST_GBD(header[index]); |
---|
387 | if (!gb) { |
---|
388 | GB_internal_error("Could not unfold data"); |
---|
389 | return NULL; |
---|
390 | } |
---|
391 | } |
---|
392 | return gb; |
---|
393 | } |
---|
394 | |
---|
395 | static char gb_ctype_table[256]; |
---|
396 | void gb_init_ctype_table() { |
---|
397 | int i; |
---|
398 | for (i=0; i<256; i++) { |
---|
399 | if (islower(i) || isupper(i) || isdigit(i) || i=='_' || i=='@') { |
---|
400 | gb_ctype_table[i] = 1; |
---|
401 | } |
---|
402 | else { |
---|
403 | gb_ctype_table[i] = 0; |
---|
404 | } |
---|
405 | } |
---|
406 | } |
---|
407 | |
---|
408 | inline char *gb_first_non_key_character(const char *str) { |
---|
409 | const char *s = str; |
---|
410 | int c; |
---|
411 | while (1) { |
---|
412 | c = *s; |
---|
413 | if (!gb_ctype_table[c]) { |
---|
414 | if (c == 0) break; |
---|
415 | return (char *)(s); |
---|
416 | } |
---|
417 | s++; |
---|
418 | } |
---|
419 | return NULL; |
---|
420 | } |
---|
421 | |
---|
422 | char *GB_first_non_key_char(const char *str) { |
---|
423 | return gb_first_non_key_character(str); |
---|
424 | } |
---|
425 | |
---|
426 | GBDATA *gb_search(GBDATA * gbd, const char *str, GB_TYPES create, int internflag) |
---|
427 | { |
---|
428 | /* finds a hierarchical key, |
---|
429 | if create != GB_FIND(==0), then create the key |
---|
430 | force types if ! internflag |
---|
431 | */ |
---|
432 | |
---|
433 | char *s1, *s2; |
---|
434 | GBDATA *gbp, *gbsp; |
---|
435 | int len; |
---|
436 | int separator = 0; |
---|
437 | char buffer[GB_PATH_MAX]; |
---|
438 | |
---|
439 | GB_test_transaction(gbd); |
---|
440 | if (!str) { |
---|
441 | return GB_child(gbd); |
---|
442 | } |
---|
443 | if (*str == '/') { |
---|
444 | gbd = GB_get_root(gbd); |
---|
445 | str++; |
---|
446 | } |
---|
447 | |
---|
448 | if (!gb_first_non_key_character(str)) { |
---|
449 | gbsp = GB_entry(gbd, str); |
---|
450 | if (gbsp && create) { |
---|
451 | GB_TYPES oldType = GB_TYPE(gbsp); |
---|
452 | if (create != oldType) { // type mismatch |
---|
453 | GB_export_errorf("Inconsistent type for field '%s' (existing=%i, expected=%i)", str, oldType, create); |
---|
454 | return NULL; |
---|
455 | } |
---|
456 | } |
---|
457 | if (!gbsp && create) { |
---|
458 | if (internflag) { |
---|
459 | if (create == GB_CREATE_CONTAINER) { |
---|
460 | gbsp = gb_create_container(gbd, str); |
---|
461 | } |
---|
462 | else { |
---|
463 | gbsp = gb_create(gbd, str, create); |
---|
464 | } |
---|
465 | } |
---|
466 | else { |
---|
467 | if (create == GB_CREATE_CONTAINER) { |
---|
468 | gbsp = GB_create_container(gbd, str); |
---|
469 | } |
---|
470 | else { |
---|
471 | gbsp = gb_create(gbd, str, create); |
---|
472 | } |
---|
473 | } |
---|
474 | if (!gbsp) GB_print_error(); |
---|
475 | } |
---|
476 | return gbsp; |
---|
477 | } |
---|
478 | { |
---|
479 | len = strlen(str)+1; |
---|
480 | if (len > GB_PATH_MAX) { |
---|
481 | GB_internal_errorf("Path Length '%i' exceeded by '%s'", GB_PATH_MAX, str); |
---|
482 | return NULL; |
---|
483 | } |
---|
484 | memcpy(buffer, str, len); |
---|
485 | } |
---|
486 | |
---|
487 | gbp = gbd; |
---|
488 | for (s1 = buffer; s1; s1 = s2) { |
---|
489 | |
---|
490 | s2 = gb_first_non_key_character(s1); |
---|
491 | if (s2) { |
---|
492 | separator = *s2; |
---|
493 | *(s2++) = 0; |
---|
494 | if (separator == '-') { |
---|
495 | if ((*s2) != '>') { |
---|
496 | GB_export_errorf("Invalid key for gb_search '%s'", str); |
---|
497 | GB_print_error(); |
---|
498 | return NULL; |
---|
499 | } |
---|
500 | s2++; |
---|
501 | } |
---|
502 | } |
---|
503 | |
---|
504 | if (strcmp("..", s1) == 0) { |
---|
505 | gbsp = GB_get_father(gbp); |
---|
506 | } |
---|
507 | else { |
---|
508 | gbsp = GB_entry(gbp, s1); |
---|
509 | if (gbsp && separator == '-') { // follow link !!! |
---|
510 | if (GB_TYPE(gbsp) != GB_LINK) { |
---|
511 | if (create) { |
---|
512 | GB_export_error("Cannot create links on the fly in GB_search"); |
---|
513 | GB_print_error(); |
---|
514 | } |
---|
515 | return NULL; |
---|
516 | } |
---|
517 | gbsp = GB_follow_link(gbsp); |
---|
518 | separator = 0; |
---|
519 | if (!gbsp) return NULL; // cannot resolve link |
---|
520 | } |
---|
521 | while (gbsp && create) { |
---|
522 | if (s2) { // non terminal |
---|
523 | if (GB_DB == GB_TYPE(gbsp)) break; |
---|
524 | } |
---|
525 | else { // terminal |
---|
526 | if (create == GB_TYPE(gbsp)) break; |
---|
527 | } |
---|
528 | GB_internal_errorf("Inconsistent Type %u:%u '%s':'%s', repairing database", create, GB_TYPE(gbsp), str, s1); |
---|
529 | GB_print_error(); |
---|
530 | GB_delete(gbsp); |
---|
531 | gbsp = GB_entry(gbd, s1); |
---|
532 | } |
---|
533 | } |
---|
534 | if (!gbsp) { |
---|
535 | if (!create) return NULL; // read only mode |
---|
536 | if (separator == '-') { |
---|
537 | GB_export_error("Cannot create linked objects"); |
---|
538 | return NULL; // do not create linked objects |
---|
539 | } |
---|
540 | |
---|
541 | if (s2 || (create == GB_CREATE_CONTAINER)) { |
---|
542 | gbsp = internflag |
---|
543 | ? gb_create_container(gbp, s1) |
---|
544 | : GB_create_container(gbp, s1); |
---|
545 | } |
---|
546 | else { |
---|
547 | gbsp = GB_create(gbp, s1, (GB_TYPES)create); |
---|
548 | if (create == GB_STRING) { |
---|
549 | GB_ERROR error = GB_write_string(gbsp, ""); |
---|
550 | if (error) GB_internal_error("Couldn't write to just created string entry"); |
---|
551 | } |
---|
552 | } |
---|
553 | |
---|
554 | if (!gbsp) return NULL; |
---|
555 | } |
---|
556 | gbp = gbsp; |
---|
557 | } |
---|
558 | return gbp; |
---|
559 | } |
---|
560 | |
---|
561 | |
---|
562 | GBDATA *GB_search(GBDATA * gbd, const char *fieldpath, GB_TYPES create) { |
---|
563 | return gb_search(gbd, fieldpath, create, 0); |
---|
564 | } |
---|
565 | |
---|
566 | static GBDATA *gb_expect_type(GBDATA *gbd, long expected_type, const char *fieldname) { |
---|
567 | gb_assert(expected_type != GB_FIND); // impossible |
---|
568 | |
---|
569 | long type = GB_TYPE(gbd); |
---|
570 | if (type != expected_type) { |
---|
571 | GB_export_errorf("Field '%s' has wrong type (found=%li, expected=%li)", fieldname, type, expected_type); |
---|
572 | gbd = 0; |
---|
573 | } |
---|
574 | return gbd; |
---|
575 | } |
---|
576 | |
---|
577 | GBDATA *GB_searchOrCreate_string(GBDATA *gb_container, const char *fieldpath, const char *default_value) { |
---|
578 | GBDATA *gb_str = GB_search(gb_container, fieldpath, GB_FIND); |
---|
579 | if (!gb_str) { |
---|
580 | gb_str = GB_search(gb_container, fieldpath, GB_STRING); |
---|
581 | GB_ERROR error; |
---|
582 | |
---|
583 | if (!gb_str) error = GB_await_error(); |
---|
584 | else error = GB_write_string(gb_str, default_value); |
---|
585 | |
---|
586 | if (error) { |
---|
587 | gb_str = 0; |
---|
588 | GB_export_error(error); |
---|
589 | } |
---|
590 | } |
---|
591 | else { |
---|
592 | gb_str = gb_expect_type(gb_str, GB_STRING, fieldpath); |
---|
593 | } |
---|
594 | return gb_str; |
---|
595 | } |
---|
596 | |
---|
597 | GBDATA *GB_searchOrCreate_int(GBDATA *gb_container, const char *fieldpath, long default_value) { |
---|
598 | GBDATA *gb_int = GB_search(gb_container, fieldpath, GB_FIND); |
---|
599 | if (!gb_int) { |
---|
600 | gb_int = GB_search(gb_container, fieldpath, GB_INT); |
---|
601 | GB_ERROR error; |
---|
602 | |
---|
603 | if (!gb_int) error = GB_await_error(); |
---|
604 | else error = GB_write_int(gb_int, default_value); |
---|
605 | |
---|
606 | if (error) { |
---|
607 | gb_int = 0; |
---|
608 | GB_export_error(error); |
---|
609 | } |
---|
610 | } |
---|
611 | else { |
---|
612 | gb_int = gb_expect_type(gb_int, GB_INT, fieldpath); |
---|
613 | } |
---|
614 | return gb_int; |
---|
615 | } |
---|
616 | |
---|
617 | GBDATA *GB_searchOrCreate_float(GBDATA *gb_container, const char *fieldpath, double default_value) { |
---|
618 | GBDATA *gb_float = GB_search(gb_container, fieldpath, GB_FIND); |
---|
619 | if (!gb_float) { |
---|
620 | gb_float = GB_search(gb_container, fieldpath, GB_FLOAT); |
---|
621 | GB_ERROR error; |
---|
622 | |
---|
623 | if (!gb_float) error = GB_await_error(); |
---|
624 | else error = GB_write_float(gb_float, default_value); |
---|
625 | |
---|
626 | if (error) { |
---|
627 | gb_float = 0; |
---|
628 | GB_export_error(error); |
---|
629 | } |
---|
630 | } |
---|
631 | else { |
---|
632 | gb_float = gb_expect_type(gb_float, GB_FLOAT, fieldpath); |
---|
633 | } |
---|
634 | return gb_float; |
---|
635 | } |
---|
636 | |
---|
637 | static GBDATA *gb_search_marked(GBCONTAINER *gbc, GBQUARK key_quark, int firstindex, size_t skip_over) { |
---|
638 | int userbit = GBCONTAINER_MAIN(gbc)->users[0]->userbit; |
---|
639 | int index; |
---|
640 | int end = gbc->d.nheader; |
---|
641 | gb_header_list *header = GB_DATA_LIST_HEADER(gbc->d); |
---|
642 | |
---|
643 | for (index = firstindex; index<end; index++) { |
---|
644 | GBDATA *gb; |
---|
645 | |
---|
646 | if (! (userbit & header[index].flags.flags)) continue; |
---|
647 | if ((key_quark>=0) && (header[index].flags.key_quark != key_quark)) continue; |
---|
648 | if (header[index].flags.changed >= GB_DELETED) continue; |
---|
649 | if ((gb=GB_HEADER_LIST_GBD(header[index]))==NULL) { |
---|
650 | gb_unfold(gbc, 0, index); |
---|
651 | header = GB_DATA_LIST_HEADER(gbc->d); |
---|
652 | gb = GB_HEADER_LIST_GBD(header[index]); |
---|
653 | } |
---|
654 | if (!skip_over--) return gb; |
---|
655 | } |
---|
656 | return NULL; |
---|
657 | } |
---|
658 | |
---|
659 | GBDATA *GB_search_last_son(GBDATA *gbd) { |
---|
660 | GBCONTAINER *gbc = (GBCONTAINER *)gbd; |
---|
661 | int index; |
---|
662 | int end = gbc->d.nheader; |
---|
663 | GBDATA *gb; |
---|
664 | gb_header_list *header = GB_DATA_LIST_HEADER(gbc->d); |
---|
665 | |
---|
666 | for (index = end-1; index>=0; index--) { |
---|
667 | if (header[index].flags.changed >= GB_DELETED) continue; |
---|
668 | if ((gb=GB_HEADER_LIST_GBD(header[index]))==NULL) |
---|
669 | { |
---|
670 | gb_unfold(gbc, 0, index); |
---|
671 | header = GB_DATA_LIST_HEADER(gbc->d); |
---|
672 | gb = GB_HEADER_LIST_GBD(header[index]); |
---|
673 | } |
---|
674 | return gb; |
---|
675 | } |
---|
676 | return NULL; |
---|
677 | } |
---|
678 | |
---|
679 | long GB_number_of_marked_subentries(GBDATA *gbd) { |
---|
680 | GBCONTAINER *gbc = (GBCONTAINER *)gbd; |
---|
681 | int userbit = GBCONTAINER_MAIN(gbc)->users[0]->userbit; |
---|
682 | int index; |
---|
683 | int end = gbc->d.nheader; |
---|
684 | gb_header_list *header; |
---|
685 | long count = 0; |
---|
686 | |
---|
687 | header = GB_DATA_LIST_HEADER(gbc->d); |
---|
688 | for (index = 0; index<end; index++) { |
---|
689 | if (! (userbit & header[index].flags.flags)) continue; |
---|
690 | if (header[index].flags.changed >= GB_DELETED) continue; |
---|
691 | count++; |
---|
692 | } |
---|
693 | return count; |
---|
694 | } |
---|
695 | |
---|
696 | |
---|
697 | |
---|
698 | GBDATA *GB_first_marked(GBDATA *gbd, const char *keystring) { |
---|
699 | GBCONTAINER *gbc = (GBCONTAINER *)gbd; |
---|
700 | GBQUARK key_quark; |
---|
701 | if (keystring) { |
---|
702 | key_quark = GB_key_2_quark(gbd, keystring); |
---|
703 | } |
---|
704 | else { |
---|
705 | key_quark = -1; |
---|
706 | } |
---|
707 | GB_test_transaction(gbd); |
---|
708 | return gb_search_marked(gbc, key_quark, 0, 0); |
---|
709 | } |
---|
710 | |
---|
711 | |
---|
712 | GBDATA *GB_following_marked(GBDATA *gbd, const char *keystring, size_t skip_over) { |
---|
713 | GBCONTAINER *gbc = GB_FATHER(gbd); |
---|
714 | GBQUARK key_quark; |
---|
715 | |
---|
716 | if (keystring) { |
---|
717 | key_quark = GB_key_2_quark(gbd, keystring); |
---|
718 | } |
---|
719 | else { |
---|
720 | key_quark = -1; |
---|
721 | } |
---|
722 | GB_test_transaction(gbd); |
---|
723 | return gb_search_marked(gbc, key_quark, (int)gbd->index+1, skip_over); |
---|
724 | } |
---|
725 | |
---|
726 | GBDATA *GB_next_marked(GBDATA *gbd, const char *keystring) { |
---|
727 | return GB_following_marked(gbd, keystring, 0); |
---|
728 | } |
---|
729 | |
---|
730 | // ---------------------------- |
---|
731 | // Command interpreter |
---|
732 | |
---|
733 | void gb_install_command_table(GBDATA *gb_main, struct GBL_command_table *table, size_t table_size) |
---|
734 | { |
---|
735 | GB_MAIN_TYPE *Main = GB_MAIN(gb_main); |
---|
736 | if (!Main->command_hash) Main->command_hash = GBS_create_hash(table_size, GB_IGNORE_CASE); |
---|
737 | |
---|
738 | for (; table->command_identifier; table++) { |
---|
739 | GBS_write_hash(Main->command_hash, table->command_identifier, (long)table->function); |
---|
740 | } |
---|
741 | |
---|
742 | gb_assert((GBS_hash_count_elems(Main->command_hash)+1) == table_size); |
---|
743 | } |
---|
744 | |
---|
745 | static char *gbs_search_second_x(const char *str) { |
---|
746 | int c; |
---|
747 | for (; (c=*str); str++) { |
---|
748 | if (c=='\\') { // escaped characters |
---|
749 | str++; |
---|
750 | if (!(c=*str)) return NULL; |
---|
751 | continue; |
---|
752 | } |
---|
753 | if (c=='"') return (char *)str; |
---|
754 | } |
---|
755 | return NULL; |
---|
756 | } |
---|
757 | |
---|
758 | char *gbs_search_second_bracket(const char *source) |
---|
759 | { |
---|
760 | int c; |
---|
761 | int deep = 0; |
---|
762 | if (*source != '(') deep --; // first bracket |
---|
763 | for (; (c=*source); source++) { |
---|
764 | if (c=='\\') { // escaped characters |
---|
765 | source++; |
---|
766 | if (!*source) break; |
---|
767 | continue; |
---|
768 | } |
---|
769 | if (c=='(') deep--; |
---|
770 | else if (c==')') deep++; |
---|
771 | if (!deep) return (char *)source; |
---|
772 | if (c=='"') { // search the second " |
---|
773 | source = gbs_search_second_x(source); |
---|
774 | if (!source) return NULL; |
---|
775 | } |
---|
776 | } |
---|
777 | if (!c) return NULL; |
---|
778 | return (char *)source; |
---|
779 | } |
---|
780 | |
---|
781 | |
---|
782 | static char *gbs_search_next_separator(const char *source, const char *seps) { |
---|
783 | // search the next separator |
---|
784 | static char tab[256]; |
---|
785 | static int flag = 0; |
---|
786 | int c; |
---|
787 | const char *p; |
---|
788 | if (!flag) { |
---|
789 | flag = 1; |
---|
790 | memset(tab, 0, 256); |
---|
791 | } |
---|
792 | for (p = seps; (c=*p); p++) tab[c] = 1; // tab[seps[x]] = 1 |
---|
793 | tab['('] = 1; // exclude () pairs |
---|
794 | tab['"'] = 1; // exclude " pairs |
---|
795 | tab['\\'] = 1; // exclude \-escaped chars |
---|
796 | |
---|
797 | for (; (c=*source); source++) { |
---|
798 | if (tab[c]) { |
---|
799 | if (c=='\\') { |
---|
800 | source++; |
---|
801 | continue; |
---|
802 | } |
---|
803 | if (c=='(') { |
---|
804 | source = gbs_search_second_bracket(source); |
---|
805 | if (!source) break; |
---|
806 | continue; |
---|
807 | } |
---|
808 | if (c=='"') { |
---|
809 | source = gbs_search_second_x(source+1); |
---|
810 | if (!source) break; |
---|
811 | continue; |
---|
812 | } |
---|
813 | for (p = seps; (c=*p); p++) tab[c] = 0; |
---|
814 | return (char *)source; |
---|
815 | } |
---|
816 | } |
---|
817 | for (p = seps; (c=*p); p++) tab[c] = 0; // clear tab |
---|
818 | return NULL; |
---|
819 | } |
---|
820 | |
---|
821 | static void dumpStreams(const char *name, int count, const GBL *args) { |
---|
822 | printf("%s=%i\n", name, count); |
---|
823 | if (count > 0) { |
---|
824 | int c; |
---|
825 | for (c = 0; c<count; c++) { |
---|
826 | printf(" %02i='%s'\n", c, args[c].str); |
---|
827 | } |
---|
828 | } |
---|
829 | } |
---|
830 | |
---|
831 | static const char *shortenLongString(const char *str, size_t wanted_len) { |
---|
832 | // shortens the string 'str' to 'wanted_len' (appends '[..]' if string was shortened) |
---|
833 | |
---|
834 | const char *result; |
---|
835 | size_t len = strlen(str); |
---|
836 | |
---|
837 | gb_assert(wanted_len>4); |
---|
838 | |
---|
839 | if (len>wanted_len) { |
---|
840 | static char *shortened_str; |
---|
841 | static size_t short_len = 0; |
---|
842 | |
---|
843 | if (short_len >= wanted_len) { |
---|
844 | memcpy(shortened_str, str, wanted_len-4); |
---|
845 | } |
---|
846 | else { |
---|
847 | freeset(shortened_str, GB_strpartdup(str, str+wanted_len)); |
---|
848 | short_len = wanted_len; |
---|
849 | } |
---|
850 | strcpy(shortened_str+wanted_len-4, "[..]"); |
---|
851 | result = shortened_str; |
---|
852 | } |
---|
853 | else { |
---|
854 | result = str; |
---|
855 | } |
---|
856 | return result; |
---|
857 | } |
---|
858 | |
---|
859 | #if defined(WARN_TODO) |
---|
860 | #warning rewrite GB_command_interpreter (error+ressource handling) |
---|
861 | #endif |
---|
862 | |
---|
863 | char *GB_command_interpreter(GBDATA *gb_main, const char *str, const char *commands, GBDATA *gbd, const char *default_tree_name) { |
---|
864 | /* simple command interpreter returns NULL on error (which should be exported in that case) |
---|
865 | * if first character is == ':' run string parser |
---|
866 | * if first character is == '/' run regexpr |
---|
867 | * else command interpreter |
---|
868 | */ |
---|
869 | int strmalloc = 0; |
---|
870 | char *buffer; |
---|
871 | GB_ERROR error; |
---|
872 | int i; |
---|
873 | int argcinput; |
---|
874 | int argcparam; |
---|
875 | int argcout; |
---|
876 | char *bracket; |
---|
877 | GB_MAIN_TYPE *Main = GB_MAIN(gb_main); |
---|
878 | |
---|
879 | GBL morig[GBL_MAX_ARGUMENTS]; |
---|
880 | GBL min[GBL_MAX_ARGUMENTS]; |
---|
881 | GBL mout[GBL_MAX_ARGUMENTS]; |
---|
882 | |
---|
883 | GBL *orig = & morig[0]; |
---|
884 | GBL *in = & min[0]; |
---|
885 | GBL *out = & mout[0]; |
---|
886 | int trace = GB_get_ACISRT_trace(); |
---|
887 | |
---|
888 | if (!str) { |
---|
889 | if (!gbd) { |
---|
890 | GB_export_error("ACI: no input streams found"); |
---|
891 | return NULL; |
---|
892 | } |
---|
893 | str = GB_read_as_string(gbd); |
---|
894 | strmalloc = 1; |
---|
895 | } |
---|
896 | |
---|
897 | if (trace) { |
---|
898 | printf("GB_command_interpreter: str='%s'\n" |
---|
899 | " command='%s'\n", str, commands); |
---|
900 | } |
---|
901 | |
---|
902 | if (!commands || !commands[0]) { // empty command -> do not modify string |
---|
903 | if (!strmalloc) return strdup(str); |
---|
904 | return (char *)str; |
---|
905 | } |
---|
906 | |
---|
907 | if (commands[0] == ':') { // ':' -> string parser |
---|
908 | return GBS_string_eval(str, commands+1, gbd); |
---|
909 | } |
---|
910 | |
---|
911 | if (commands[0] == '/') { // regular expression |
---|
912 | GB_ERROR err = 0; |
---|
913 | char *result = GBS_regreplace(str, commands, &err); |
---|
914 | |
---|
915 | if (!result) { |
---|
916 | if (strcmp(err, "Missing '/' between search and replace string") == 0) { |
---|
917 | // if GBS_regreplace didn't find a third '/' -> silently use GBS_regmatch: |
---|
918 | size_t matchlen; |
---|
919 | err = 0; |
---|
920 | const char *matched = GBS_regmatch(str, commands, &matchlen, &err); |
---|
921 | |
---|
922 | if (matched) result = GB_strndup(matched, matchlen); |
---|
923 | else if (!err) result = strdup(""); |
---|
924 | } |
---|
925 | |
---|
926 | if (!result && err) result = GBS_global_string_copy("<Error: %s>", err); |
---|
927 | } |
---|
928 | return result; |
---|
929 | } |
---|
930 | |
---|
931 | // ********************** init ******************* |
---|
932 | |
---|
933 | gb_local->gbl.gb_main = gb_main; |
---|
934 | buffer = strdup(commands); |
---|
935 | |
---|
936 | // ********************** remove all spaces and tabs ******************* |
---|
937 | { |
---|
938 | const char *s1; |
---|
939 | char *s2; |
---|
940 | s1 = commands; |
---|
941 | s2 = buffer; |
---|
942 | { |
---|
943 | int c; |
---|
944 | for (; (c = *s1); s1++) { |
---|
945 | if (c=='\\') { |
---|
946 | *(s2++) = c; |
---|
947 | if (!(c=*s1)) { break; } |
---|
948 | *(s2++) = c; |
---|
949 | continue; |
---|
950 | } |
---|
951 | |
---|
952 | if (c=='"') { // search the second " |
---|
953 | const char *hp = gbs_search_second_x(s1+1); |
---|
954 | if (!hp) { |
---|
955 | GB_export_errorf("unbalanced '\"' in '%s'", commands); |
---|
956 | return NULL; |
---|
957 | } |
---|
958 | while (s1 <= hp) *(s2++) = *(s1++); |
---|
959 | s1--; |
---|
960 | continue; |
---|
961 | } |
---|
962 | if (c!=' ' && c!='\t') *(s2++) = c; |
---|
963 | } |
---|
964 | } |
---|
965 | *s2 = 0; |
---|
966 | } |
---|
967 | |
---|
968 | |
---|
969 | |
---|
970 | memset((char *)orig, 0, sizeof(GBL)*GBL_MAX_ARGUMENTS); |
---|
971 | memset((char *)in, 0, sizeof(GBL)*GBL_MAX_ARGUMENTS); |
---|
972 | memset((char *)out, 0, sizeof(GBL)*GBL_MAX_ARGUMENTS); |
---|
973 | |
---|
974 | if (strmalloc) { |
---|
975 | orig[0].str = (char *)str; |
---|
976 | } |
---|
977 | else { |
---|
978 | orig[0].str = strdup(str); |
---|
979 | } |
---|
980 | |
---|
981 | argcinput = 1; |
---|
982 | argcout = 0; |
---|
983 | error = 0; |
---|
984 | { |
---|
985 | char *s1, *s2; |
---|
986 | s1 = buffer; |
---|
987 | if (*s1 == '|') s1++; |
---|
988 | |
---|
989 | // ** loop over all commands ** |
---|
990 | for (s1 = s1; s1; s1 = s2) { |
---|
991 | int separator; |
---|
992 | GBL_COMMAND command; |
---|
993 | s2 = gbs_search_next_separator(s1, "|;,"); |
---|
994 | if (s2) { |
---|
995 | separator = *(s2); |
---|
996 | *(s2++) = 0; |
---|
997 | } |
---|
998 | else { |
---|
999 | separator = 0; |
---|
1000 | } |
---|
1001 | // collect the parameters |
---|
1002 | memset((char*)in, 0, sizeof(GBL)*GBL_MAX_ARGUMENTS); |
---|
1003 | if (*s1 == '"') { // copy "text" to out |
---|
1004 | char *end = gbs_search_second_x(s1+1); |
---|
1005 | if (!end) { |
---|
1006 | error = "Missing second '\"'"; |
---|
1007 | break; |
---|
1008 | } |
---|
1009 | *end = 0; |
---|
1010 | out[argcout++].str = strdup(s1+1); |
---|
1011 | } |
---|
1012 | else { |
---|
1013 | argcparam = 0; |
---|
1014 | bracket = strchr(s1, '('); |
---|
1015 | if (bracket) { // I got the parameter list |
---|
1016 | int slen; |
---|
1017 | *(bracket++) = 0; |
---|
1018 | slen = strlen(bracket); |
---|
1019 | if (bracket[slen-1] != ')') { |
---|
1020 | error = "Missing ')'"; |
---|
1021 | } |
---|
1022 | else { |
---|
1023 | // go through the parameters |
---|
1024 | char *p1, *p2; |
---|
1025 | bracket[slen-1] = 0; |
---|
1026 | for (p1 = bracket; p1; p1 = p2) { |
---|
1027 | p2 = gbs_search_next_separator(p1, ";,"); |
---|
1028 | if (p2) { |
---|
1029 | *(p2++) = 0; |
---|
1030 | } |
---|
1031 | if (p1[0] == '"') { // remove "" pairs |
---|
1032 | int len2; |
---|
1033 | p1++; |
---|
1034 | len2 = strlen(p1)-1; |
---|
1035 | |
---|
1036 | if (p1[len2] != '\"') { |
---|
1037 | error = "Missing '\"'"; |
---|
1038 | } |
---|
1039 | else { |
---|
1040 | p1[len2] = 0; |
---|
1041 | } |
---|
1042 | } |
---|
1043 | in[argcparam++].str = strdup(p1); |
---|
1044 | } |
---|
1045 | } |
---|
1046 | if (error) break; |
---|
1047 | } |
---|
1048 | if (!error && (bracket || *s1)) { |
---|
1049 | char *p = s1; |
---|
1050 | int c; |
---|
1051 | while ((c = *p)) { // command to lower case |
---|
1052 | if (c>='A' && c<='Z') { |
---|
1053 | c += 'a'-'A'; |
---|
1054 | *p = c; |
---|
1055 | } |
---|
1056 | p++; |
---|
1057 | } |
---|
1058 | |
---|
1059 | command = (GBL_COMMAND)GBS_read_hash(Main->command_hash, s1); |
---|
1060 | if (!command) { |
---|
1061 | error = GBS_global_string("Unknown command '%s'", s1); |
---|
1062 | } |
---|
1063 | else { |
---|
1064 | GBL_command_arguments args; |
---|
1065 | args.gb_ref = gbd; |
---|
1066 | args.default_tree_name = default_tree_name; |
---|
1067 | args.command = s1; |
---|
1068 | args.cinput = argcinput; |
---|
1069 | args.vinput = orig; |
---|
1070 | args.cparam = argcparam; |
---|
1071 | args.vparam = in; |
---|
1072 | args.coutput = &argcout; |
---|
1073 | args.voutput = &out; |
---|
1074 | |
---|
1075 | if (trace) { |
---|
1076 | printf("-----------------------\nExecution of command '%s':\n", args.command); |
---|
1077 | dumpStreams("Arguments", args.cparam, args.vparam); |
---|
1078 | dumpStreams("InputStreams", args.cinput, args.vinput); |
---|
1079 | } |
---|
1080 | |
---|
1081 | error = command(&args); // execute the command |
---|
1082 | |
---|
1083 | if (!error && trace) dumpStreams("OutputStreams", *args.coutput, *args.voutput); |
---|
1084 | |
---|
1085 | if (error) { |
---|
1086 | char *inputstreams = 0; |
---|
1087 | char *paramlist = 0; |
---|
1088 | int j; |
---|
1089 | |
---|
1090 | #define MAX_PRINT_LEN 200 |
---|
1091 | |
---|
1092 | for (j = 0; j<args.cparam; ++j) { |
---|
1093 | const char *param = args.vparam[j].str; |
---|
1094 | const char *param_short = shortenLongString(param, MAX_PRINT_LEN); |
---|
1095 | |
---|
1096 | if (!paramlist) paramlist = strdup(param_short); |
---|
1097 | else freeset(paramlist, GBS_global_string_copy("%s,%s", paramlist, param_short)); |
---|
1098 | } |
---|
1099 | for (j = 0; j<args.cinput; ++j) { |
---|
1100 | const char *param = args.vinput[j].str; |
---|
1101 | const char *param_short = shortenLongString(param, MAX_PRINT_LEN); |
---|
1102 | |
---|
1103 | if (!inputstreams) inputstreams = strdup(param_short); |
---|
1104 | else freeset(inputstreams, GBS_global_string_copy("%s;%s", inputstreams, param_short)); |
---|
1105 | } |
---|
1106 | #undef MAX_PRINT_LEN |
---|
1107 | if (paramlist) { |
---|
1108 | error = GBS_global_string("while applying '%s(%s)'\nto '%s':\n%s", s1, paramlist, inputstreams, error); |
---|
1109 | } |
---|
1110 | else { |
---|
1111 | error = GBS_global_string("while applying '%s'\nto '%s':\n%s", s1, inputstreams, error); |
---|
1112 | } |
---|
1113 | |
---|
1114 | free(inputstreams); |
---|
1115 | free(paramlist); |
---|
1116 | } |
---|
1117 | } |
---|
1118 | } |
---|
1119 | |
---|
1120 | for (i=0; i<argcparam; i++) { // free intermediate arguments |
---|
1121 | if (in[i].str) free(in[i].str); |
---|
1122 | } |
---|
1123 | } |
---|
1124 | |
---|
1125 | if (error) break; |
---|
1126 | |
---|
1127 | if (separator == '|') { // swap in and out in pipes |
---|
1128 | GBL *h; |
---|
1129 | for (i=0; i<argcinput; i++) { |
---|
1130 | if (orig[i].str) free(orig[i].str); |
---|
1131 | } |
---|
1132 | memset((char*)orig, 0, sizeof(GBL)*GBL_MAX_ARGUMENTS); |
---|
1133 | argcinput = 0; |
---|
1134 | |
---|
1135 | h = out; // swap orig and out |
---|
1136 | out = orig; |
---|
1137 | orig = h; |
---|
1138 | |
---|
1139 | argcinput = argcout; |
---|
1140 | argcout = 0; |
---|
1141 | } |
---|
1142 | |
---|
1143 | } |
---|
1144 | } |
---|
1145 | for (i=0; i<argcinput; i++) { |
---|
1146 | if (orig[i].str) free(orig[i].str); |
---|
1147 | } |
---|
1148 | |
---|
1149 | { |
---|
1150 | char *s1; |
---|
1151 | if (!argcout) { |
---|
1152 | s1 = strdup(""); // returned '<NULL>' in the past |
---|
1153 | } |
---|
1154 | else if (argcout == 1) { |
---|
1155 | s1 = out[0].str; |
---|
1156 | } |
---|
1157 | else { // concatenate output strings |
---|
1158 | GBS_strstruct *strstruct = GBS_stropen(1000); |
---|
1159 | for (i=0; i<argcout; i++) { |
---|
1160 | if (out[i].str) { |
---|
1161 | GBS_strcat(strstruct, out[i].str); |
---|
1162 | free(out[i].str); |
---|
1163 | } |
---|
1164 | } |
---|
1165 | s1 = GBS_strclose(strstruct); |
---|
1166 | } |
---|
1167 | free(buffer); |
---|
1168 | |
---|
1169 | if (!error) { |
---|
1170 | if (trace) printf("GB_command_interpreter: result='%s'\n", s1); |
---|
1171 | return s1; |
---|
1172 | } |
---|
1173 | free(s1); |
---|
1174 | } |
---|
1175 | |
---|
1176 | GB_export_errorf("Command '%s' failed:\nReason: %s", commands, error); |
---|
1177 | return NULL; |
---|
1178 | } |
---|
1179 | |
---|