ARB
adquery.cxx
Go to the documentation of this file.
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 #include <algorithm>
18 
19 #include <arb_strbuf.h>
20 #include <arb_match.h>
21 
22 #include <cctype>
23 
24 #define GB_PATH_MAX 1024
25 
26 static void build_GBDATA_path(GBDATA *gbd, char **buffer) {
27  GBCONTAINER *gbc = GB_FATHER(gbd);
28  if (gbc) {
29  build_GBDATA_path(gbc, buffer);
30 
31  const char *key = GB_KEY(gbd);
32  char *bp = *buffer;
33 
34  *bp++ = '/';
35  while (*key) *bp++ = *key++;
36  *bp = 0;
37 
38  *buffer = bp;
39  }
40 }
41 
42 #define BUFFERSIZE 1024
43 
44 static const char *GB_get_GBDATA_path(GBDATA *gbd) {
45  static char *orgbuffer = NULp;
46  char *buffer;
47 
48  if (!orgbuffer) ARB_alloc(orgbuffer, 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();
65  gb_assert(val);
66  if (type == GB_STRING) {
67  gb_assert(gb->is_a_string()); // 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  equal = GBS_string_matches(GB_read_char_pntr(gb), val, case_sens);
77  break;
78 
79  case GB_INT: {
80  int i = GB_read_int(gb);
81  if (i == *(int*)val) equal = true;
82  break;
83  }
84  default: {
85  const char *err = GBS_global_string("Value search not supported for data type %i (%i)", gb->type(), type);
86  GB_internal_error(err);
87  break;
88  }
89  }
90 
91  return equal;
92 }
93 
94 static GBDATA *find_sub_by_quark(GBCONTAINER *father, GBQUARK key_quark, GB_TYPES type, const char *val, GB_CASE case_sens, GBDATA *after, size_t skip_over) {
95  /* search an entry with a key 'key_quark' below a container 'father'
96  after position 'after'
97 
98  if 'skip_over' > 0 search skips 'skip_over' entries
99 
100  if 'val' specified -> search for entry with value 'val':
101 
102  GB_STRING/GB_LINK: compares string (case_sensitive or not)
103  GB_INT: compares values
104  GB_FLOAT: ditto (val MUST be a 'double*')
105  others: not implemented yet
106 
107  Note: to search for non-char*-values use GB_find_int()
108  for other types write a new similar function
109 
110  if key_quark<0 search everything
111  */
112 
113  int end = father->d.nheader;
114  gb_header_list *header = GB_DATA_LIST_HEADER(father->d);
115 
116  int index;
117  if (after) index = (int)after->index+1; else index = 0;
118 
119  if (key_quark<0) { // unspecific key quark (i.e. search all)
120  gb_assert(!val); // search for val not possible if searching all keys!
121  if (!val) {
122  for (; index < end; index++) {
123  if (header[index].flags.key_quark != 0) {
124  if (header[index].flags.changed >= GB_DELETED) continue;
125  GBDATA *gb = GB_HEADER_LIST_GBD(header[index]);
126  if (!gb) {
127  // @@@ DRY here versus below
128  gb_unfold(father, 0, index);
129  header = GB_DATA_LIST_HEADER(father->d);
130  gb = GB_HEADER_LIST_GBD(header[index]);
131  if (!gb) {
132  const char *err = GBS_global_string("Database entry #%u is missing (in '%s')", index, GB_get_GBDATA_path(father));
133  GB_internal_error(err);
134  continue;
135  }
136  }
137  if (!skip_over--) return gb;
138  }
139  }
140  }
141  }
142  else { // specific key quark
143  for (; index < end; index++) {
144  if (key_quark == header[index].flags.key_quark) {
145  if (header[index].flags.changed >= GB_DELETED) continue;
146  GBDATA *gb = GB_HEADER_LIST_GBD(header[index]);
147  if (!gb) {
148  // @@@ DRY here versus section above
149  gb_unfold(father, 0, index);
150  header = GB_DATA_LIST_HEADER(father->d);
151  gb = GB_HEADER_LIST_GBD(header[index]);
152  if (!gb) {
153  const char *err = GBS_global_string("Database entry #%u is missing (in '%s')", index, GB_get_GBDATA_path(father));
154  GB_internal_error(err);
155  continue;
156  }
157  }
158  if (val) {
159  if (!gb) {
160  GB_internal_error("Cannot unfold data");
161  continue;
162  }
163  else {
164  if (!gb_find_value_equal(gb, type, val, case_sens)) continue;
165  }
166  }
167  if (!skip_over--) return gb;
168  }
169  }
170  }
171  return NULp;
172 }
173 
174 GBDATA *GB_find_sub_by_quark(GBDATA *father, GBQUARK key_quark, GBDATA *after, size_t skip_over) {
175  return find_sub_by_quark(father->expect_container(), key_quark, GB_NONE, NULp, GB_MIND_CASE, after, skip_over);
176 }
177 
178 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) {
179  return find_sub_by_quark(father->expect_container(), key_quark, type, val, case_sens, after, skip_over);
180 }
181 
182 static GBDATA *find_sub_sub_by_quark(GBCONTAINER *const father, const char *key, GBQUARK sub_key_quark, GB_TYPES type, const char *val, GB_CASE case_sens, GBDATA *after) {
183  gb_index_files *ifs = NULp;
184  GB_MAIN_TYPE *Main = GBCONTAINER_MAIN(father);
185  int end = father->d.nheader;
186  gb_header_list *header = GB_DATA_LIST_HEADER(father->d);
187 
188  int index;
189  if (after) index = (int)after->index+1; else index = 0;
190 
191  GBDATA *res;
192  // ****** look for any hash index tables ********
193  // ****** no wildcards allowed *******
194  if (Main->is_client()) {
195  if (father->flags2.folded_container) {
196  // do the query in the server
197  if (GB_ARRAY_FLAGS(father).changed) {
198  if (!father->flags2.update_in_server) {
199  GB_ERROR error = Main->send_update_to_server(father);
200  if (error) {
201  GB_export_error(error);
202  return NULp;
203  }
204  }
205  }
206  }
207  if (father->d.size > GB_MAX_LOCAL_SEARCH && val) {
208  if (after) res = GBCMC_find(after, key, type, val, case_sens, SEARCH_CHILD_OF_NEXT);
209  else res = GBCMC_find(father, key, type, val, case_sens, SEARCH_GRANDCHILD);
210  return res;
211  }
212  }
213  if (val &&
214  (ifs=GBCONTAINER_IFS(father)) &&
215  (!strchr(val, '*')) &&
216  (!strchr(val, '?')))
217  {
218  for (; ifs; ifs = GB_INDEX_FILES_NEXT(ifs)) {
219  if (ifs->key != sub_key_quark) continue;
220  // ***** We found the index table *****
221  res = gb_index_find(father, ifs, sub_key_quark, val, case_sens, index);
222  return res;
223  }
224  }
225 
226  GBDATA *gb = after ? after : NULp;
227  for (; index < end; index++) {
228  GBDATA *gbn = GB_HEADER_LIST_GBD(header[index]);
229 
230  if (header[index].flags.changed >= GB_DELETED) continue;
231  if (!gbn) {
232  if (Main->is_client()) {
233  if (gb) res = GBCMC_find(gb, key, type, val, case_sens, SEARCH_CHILD_OF_NEXT);
234  else res = GBCMC_find(father, key, type, val, case_sens, SEARCH_GRANDCHILD);
235  return res;
236  }
237  GB_internal_error("Empty item in server");
238  continue;
239  }
240  gb = gbn;
241  if (gb->is_container()) {
242  res = GB_find_subcontent_by_quark(gb, sub_key_quark, type, val, case_sens, NULp, 0);
243  if (res) return res;
244  }
245  }
246  return NULp;
247 }
248 
249 
250 static GBDATA *gb_find_internal(GBDATA *gbd, const char *key, GB_TYPES type, const char *val, GB_CASE case_sens, GB_SEARCH_TYPE gbs) {
251  GBDATA *result = NULp;
252 
253  if (gbd) {
254  GBDATA *after = NULp;
255  GBCONTAINER *gbc = NULp;
256 
257  switch (gbs) {
258  case SEARCH_NEXT_BROTHER:
259  after = gbd;
260  FALLTHROUGH;
261  case SEARCH_BROTHER:
262  gbs = SEARCH_CHILD;
263  gbc = GB_FATHER(gbd);
264  break;
265 
266  case SEARCH_CHILD:
267  case SEARCH_GRANDCHILD:
268  if (gbd->is_container()) gbc = gbd->as_container();
269  break;
270 
272  after = gbd;
273  gbs = SEARCH_GRANDCHILD;
274  gbc = GB_FATHER(gbd);
275  break;
276  }
277 
278  if (gbc) {
279  GBQUARK key_quark = GB_find_existing_quark(gbd, key);
280 
281  if (key_quark) { // only search if 'key' is known to db
282  if (gbs == SEARCH_CHILD) {
283  result = GB_find_subcontent_by_quark(gbc, key_quark, type, val, case_sens, after, 0);
284  }
285  else {
287  result = find_sub_sub_by_quark(gbc, key, key_quark, type, val, case_sens, after);
288  }
289  }
290  }
291  }
292  return result;
293 }
294 
295 GBDATA *GB_find(GBDATA *gbd, const char *key, GB_SEARCH_TYPE gbs) {
296  // normally you should not need to use GB_find!
297  // better use one of the replacement functions
298  // (GB_find_string, GB_find_int, GB_child, GB_nextChild, GB_entry, GB_nextEntry, GB_brother)
299  return gb_find_internal(gbd, key, GB_NONE, NULp, GB_CASE_UNDEFINED, gbs);
300 }
301 
302 GBDATA *GB_find_string(GBDATA *gbd, const char *key, const char *str, GB_CASE case_sens, GB_SEARCH_TYPE gbs) {
303  // search for a subentry of 'gbd' that has
304  // - fieldname 'key'
305  // - type GB_STRING and
306  // - content matching 'str'
307  // if 'case_sens' is GB_MIND_CASE, content is matched case sensitive.
308  // GBS_string_matches is used to compare (supports wildcards)
309  return gb_find_internal(gbd, key, GB_STRING, str, case_sens, gbs);
310 }
311 NOT4PERL GBDATA *GB_find_int(GBDATA *gbd, const char *key, long val, GB_SEARCH_TYPE gbs) {
312  // search for a subentry of 'gbd' that has
313  // - fieldname 'key'
314  // - type GB_INT
315  // - and value 'val'
316  return gb_find_internal(gbd, key, GB_INT, (const char *)&val, GB_CASE_UNDEFINED, gbs);
317 }
318 
319 // ----------------------------------------------------
320 // iterate over ALL subentries of a container
321 
323  // return first child (or NULp if no children)
324  return GB_find(father, NULp, SEARCH_CHILD);
325 }
327  // return next child after 'child' (or NULp if no more children)
328  return GB_find(child, NULp, SEARCH_NEXT_BROTHER);
329 }
330 
331 // ------------------------------------------------------------------------------
332 // iterate over all subentries of a container that have a specified key
333 
334 GBDATA *GB_entry(GBDATA *father, const char *key) {
335  // return first child of 'father' that has fieldname 'key'
336  // (or NULp if none found)
337  return GB_find(father, key, SEARCH_CHILD);
338 }
340  // return next child after 'entry', that has the same fieldname
341  // (or NULp if 'entry' is last one)
342  return GB_find_sub_by_quark(GB_FATHER(entry), GB_get_quark(entry), entry, 0);
343 }
344 GBDATA *GB_followingEntry(GBDATA *entry, size_t skip_over) {
345  // return following child after 'entry', that has the same fieldname
346  // (or NULp if no such entry)
347  // skips 'skip_over' entries (skip_over == 0 behaves like GB_nextEntry)
348  return GB_find_sub_by_quark(GB_FATHER(entry), GB_get_quark(entry), entry, skip_over);
349 }
350 
351 size_t GB_countEntries(GBDATA *father, const char *key) {
352  size_t count = 0;
353  GBDATA *gb_entry = GB_entry(father, key);
354  while (gb_entry) {
355  ++count;
356  gb_entry = GB_nextEntry(gb_entry);
357  }
358  return count;
359 }
360 
361 GBDATA *GB_brother(GBDATA *entry, const char *key) {
362  // searches (first) brother (before or after) of 'entry' which has field 'key'
363  // i.e. does same as GB_entry(GB_get_father(entry), key)
364  return GB_find(entry, key, SEARCH_BROTHER);
365 }
366 
368  /* get a subentry by its internal number:
369  Warning: This subentry must exists, otherwise internal error */
370 
371  gb_header_list *header = GB_DATA_LIST_HEADER(father->d);
372  if (index >= father->d.nheader || index <0) {
373  GB_internal_errorf("Index '%i' out of range [%i:%i[", index, 0, father->d.nheader);
374  return NULp;
375  }
376  if (header[index].flags.changed >= GB_DELETED || !header[index].flags.key_quark) {
377  GB_internal_error("Entry already deleted");
378  return NULp;
379  }
380 
381  GBDATA *gb = GB_HEADER_LIST_GBD(header[index]);
382  if (!gb) {
383  gb_unfold(father, 0, index);
384  header = GB_DATA_LIST_HEADER(father->d);
385  gb = GB_HEADER_LIST_GBD(header[index]);
386  if (!gb) {
387  GB_internal_error("Could not unfold data");
388  return NULp;
389  }
390  }
391  return gb;
392 }
393 
395  bool table[256];
396 public:
398  for (int i=0; i<256; i++) {
399  table[i] = islower(i) || isupper(i) || isdigit(i) || i=='_' || i=='@';
400  }
401  }
402  const char *first_non_key_character(const char *str) const {
403  while (1) {
404  int c = *str;
405  if (!table[c]) {
406  if (c == 0) break;
407  return str;
408  }
409  str++;
410  }
411  return NULp;
412  }
413 };
415 
416 const char *GB_first_non_key_char(const char *str) {
417  return keychars.first_non_key_character(str);
418 }
419 
420 inline GBDATA *find_or_create(GBCONTAINER *gb_parent, const char *key, GB_TYPES create, bool internflag) {
421  gb_assert(!keychars.first_non_key_character(key));
422 
423  GBDATA *gbd = GB_entry(gb_parent, key);
424  if (create) {
425  if (gbd) {
426  GB_TYPES oldType = gbd->type();
427  if (create != oldType) { // type mismatch
428  GB_export_errorf("Inconsistent type for field '%s' (existing=%i, expected=%i)", key, oldType, create);
429  gbd = NULp;
430  }
431  }
432  else {
433  if (create == GB_CREATE_CONTAINER) {
434  gbd = internflag ? gb_create_container(gb_parent, key) : GB_create_container(gb_parent, key);
435  }
436  else {
437  gbd = gb_create(gb_parent, key, create);
438  }
439  gb_assert(gbd || GB_have_error());
440  }
441  }
442  return gbd;
443 }
444 
445 GBDATA *gb_search(GBCONTAINER *gbc, const char *key, GB_TYPES create, int internflag) {
446  /* finds a hierarchical key,
447  * if create != GB_FIND(==0), then create the key
448  * force types if ! internflag
449  */
450 
451  gb_assert(!GB_have_error()); // illegal to enter this function when an error is exported!
452 
453  GB_test_transaction(gbc);
454 
455  if (!key) return NULp; // was allowed in the past (and returned the 1st child). now returns NULp
456 
457  if (key[0] == '/') {
458  gbc = gb_get_root(gbc);
459  key++;
460  }
461 
462  if (!key[0]) {
463  return gbc;
464  }
465 
466  GBDATA *gb_result = NULp;
467  const char *separator = keychars.first_non_key_character(key);
468  if (!separator) gb_result = find_or_create(gbc, key, create, internflag);
469  else {
470  int len = separator-key;
471  char firstKey[len+1];
472  memcpy(firstKey, key, len);
473  firstKey[len] = 0;
474 
475  char invalid_char = 0;
476 
477  switch (separator[0]) {
478  case '/': {
479  GBDATA *gb_sub = find_or_create(gbc, firstKey, create ? GB_CREATE_CONTAINER : GB_FIND, internflag);
480  if (gb_sub) {
481  if (gb_sub->is_container()) {
482  if (separator[1] == '/') {
483  GB_export_errorf("Invalid '//' in key '%s'", key);
484  }
485  else {
486  gb_result = gb_search(gb_sub->as_container(), separator+1, create, internflag);
487  }
488  }
489  else {
490  GB_export_errorf("terminal entry '%s' cannot be used as container", firstKey);
491  }
492  }
493  break;
494  }
495  case '.': {
496  if (separator[1] != '.') invalid_char = separator[0];
497  else {
498  GBCONTAINER *gb_parent = gbc->get_father();
499  if (gb_parent) {
500  switch (separator[2]) {
501  case 0: gb_result = gb_parent; break;
502  case '/': gb_result = gb_search(gb_parent, separator+3, create, internflag); break;
503  default:
504  GB_export_errorf("Expected '/' after '..' in key '%s'", key);
505  break;
506  }
507  }
508  else { // ".." at root-node
509  if (create) {
510  GB_export_error("cannot use '..' at root node");
511  }
512  }
513  }
514  break;
515  }
516  default:
517  invalid_char = separator[0];
518  break;
519  }
520 
521  if (invalid_char) {
522  gb_assert(!gb_result);
523  GB_export_errorf("Invalid char '%c' in key '%s'", invalid_char, key);
524  }
525  }
526  gb_assert(!(gb_result && GB_have_error()));
527  return gb_result;
528 }
529 
530 
531 GBDATA *GB_search(GBDATA *gbd, const char *fieldpath, GB_TYPES create) {
532  return gb_search(gbd->expect_container(), fieldpath, create, 0);
533 }
534 
535 static GBDATA *gb_expect_type(GBDATA *gbd, GB_TYPES expected_type, const char *fieldname) {
536  gb_assert(expected_type != GB_FIND); // impossible
537 
538  GB_TYPES type = gbd->type();
539  if (type != expected_type) {
540  GB_export_errorf("Field '%s' has wrong type (found=%i, expected=%i)", fieldname, type, expected_type);
541  gbd = NULp;
542  }
543  return gbd;
544 }
545 
546 GBDATA *GB_searchOrCreate_string(GBDATA *gb_container, const char *fieldpath, const char *default_value) {
547  gb_assert(!GB_have_error()); // illegal to enter this function when an error is exported!
548 
549  GBDATA *gb_str = GB_search(gb_container, fieldpath, GB_FIND);
550  if (!gb_str) {
551  GB_clear_error();
552  gb_str = GB_search(gb_container, fieldpath, GB_STRING);
553  GB_ERROR error;
554 
555  if (!gb_str) error = GB_await_error();
556  else error = GB_write_string(gb_str, default_value);
557 
558  if (error) {
559  gb_str = NULp;
560  GB_export_error(error);
561  }
562  }
563  else {
564  gb_str = gb_expect_type(gb_str, GB_STRING, fieldpath);
565  }
566  return gb_str;
567 }
568 
569 GBDATA *GB_searchOrCreate_int(GBDATA *gb_container, const char *fieldpath, long default_value) {
570  gb_assert(!GB_have_error()); // illegal to enter this function when an error is exported!
571 
572  GBDATA *gb_int = GB_search(gb_container, fieldpath, GB_FIND);
573  if (!gb_int) {
574  gb_int = GB_search(gb_container, fieldpath, GB_INT);
575  GB_ERROR error;
576 
577  if (!gb_int) error = GB_await_error();
578  else error = GB_write_int(gb_int, default_value);
579 
580  if (error) { // @@@ in case GB_search returned 0, gb_int already is 0 and error is exported. just assert error is exported
581  gb_int = NULp;
582  GB_export_error(error);
583  }
584  }
585  else {
586  gb_int = gb_expect_type(gb_int, GB_INT, fieldpath);
587  }
588  return gb_int;
589 }
590 
591 GBDATA *GB_searchOrCreate_float(GBDATA *gb_container, const char *fieldpath, float default_value) {
592  gb_assert(!GB_have_error()); // illegal to enter this function when an error is exported!
593 
594  GBDATA *gb_float = GB_search(gb_container, fieldpath, GB_FIND);
595  if (!gb_float) {
596  gb_float = GB_search(gb_container, fieldpath, GB_FLOAT);
597  GB_ERROR error;
598 
599  if (!gb_float) error = GB_await_error();
600  else error = GB_write_float(gb_float, default_value);
601 
602  if (error) {
603  gb_float = NULp;
604  GB_export_error(error);
605  }
606  }
607  else {
608  gb_float = gb_expect_type(gb_float, GB_FLOAT, fieldpath);
609  }
610  return gb_float;
611 }
612 
613 static GBDATA *gb_search_marked(GBCONTAINER *gbc, GBQUARK key_quark, int firstindex, size_t skip_over) {
614  int userbit = GBCONTAINER_MAIN(gbc)->users[0]->userbit;
615  int index;
616  int end = gbc->d.nheader;
617  gb_header_list *header = GB_DATA_LIST_HEADER(gbc->d);
618 
619  for (index = firstindex; index<end; index++) {
620  GBDATA *gb;
621 
622  if (! (userbit & header[index].flags.flags)) continue;
623  if ((key_quark>=0) && (header[index].flags.key_quark != key_quark)) continue;
624  if (header[index].flags.changed >= GB_DELETED) continue;
625  if (!(gb=GB_HEADER_LIST_GBD(header[index]))) {
626  gb_unfold(gbc, 0, index);
627  header = GB_DATA_LIST_HEADER(gbc->d);
628  gb = GB_HEADER_LIST_GBD(header[index]);
629  }
630  if (!skip_over--) return gb;
631  }
632  return NULp;
633 }
634 
636  long count = 0;
637  if (gbd->is_container()) {
638  GBCONTAINER *gbc = gbd->as_container();
639  gb_header_list *header = GB_DATA_LIST_HEADER(gbc->d);
640 
641  int userbit = GBCONTAINER_MAIN(gbc)->users[0]->userbit;
642  int end = gbc->d.nheader;
643 
644  for (int index = 0; index<end; index++) {
645  if (!(userbit & header[index].flags.flags)) continue;
646  if (header[index].flags.changed >= GB_DELETED) continue;
647  count++;
648  }
649  }
650  return count;
651 }
652 
653 
654 
655 GBDATA *GB_first_marked(GBDATA *gbd, const char *keystring) {
656  GBCONTAINER *gbc = gbd->expect_container();
657  GBQUARK key_quark = GB_find_existing_quark(gbd, keystring);
658  GB_test_transaction(gbc);
659  return key_quark ? gb_search_marked(gbc, key_quark, 0, 0) : NULp;
660 }
661 
662 
663 GBDATA *GB_following_marked(GBDATA *gbd, const char *keystring, size_t skip_over) {
664  GBCONTAINER *gbc = GB_FATHER(gbd);
665  GBQUARK key_quark = GB_find_existing_quark(gbd, keystring);
666  GB_test_transaction(gbc);
667  return key_quark ? gb_search_marked(gbc, key_quark, (int)gbd->index+1, skip_over) : NULp;
668 }
669 
670 GBDATA *GB_next_marked(GBDATA *gbd, const char *keystring) {
671  return GB_following_marked(gbd, keystring, 0);
672 }
673 
674 
675 #ifdef UNIT_TESTS
676 #include <test_unit.h>
677 
678 struct TestDB : virtual Noncopyable {
679  GB_shell shell;
680  GBDATA *gb_main;
681  GB_ERROR error;
682 
683  GBDATA *gb_cont1;
684  GBDATA *gb_cont2;
685  GBDATA *gb_cont_empty;
686  GBDATA *gb_cont_misc;
687 
688  GB_ERROR create_many_items(GBDATA *gb_parent, const char **item_key_list, int item_count) {
689  int k = 0;
690  for (int i = 0; i<item_count && !error; i++) {
691  const char *item_key = item_key_list[k++];
692  if (!item_key) { item_key = item_key_list[0]; k = 1; }
693 
694  GBDATA *gb_child = GB_create_container(gb_parent, item_key);
695  if (!gb_child) {
696  error = GB_await_error();
697  }
698  else {
699  if ((i%7) == 0) GB_write_flag(gb_child, 1); // mark some
700 
701  GBDATA *gb_name = GB_create(gb_child, "name", GB_STRING);
702  error = GB_write_string(gb_name, GBS_global_string("%s %i", item_key, i));
703  }
704  }
705  return error;
706  }
707 
708  TestDB() {
709  gb_main = GB_open("nosuch.arb", "c");
710  error = gb_main ? NULp : GB_await_error();
711 
712  if (!error) {
713  GB_transaction ta(gb_main);
714  gb_cont1 = GB_create_container(gb_main, "container1");
715  gb_cont2 = GB_create_container(gb_main, "container2");
716  gb_cont_empty = GB_create_container(gb_main, "empty");
717  gb_cont_misc = GB_create_container(gb_main, "misc");
718 
719  if (!gb_cont1 || !gb_cont2) error = GB_await_error();
720 
721  const char *single_key[] = { "entry", NULp };
722  const char *mixed_keys[] = { "item", "other", NULp };
723 
724  if (!error) error = create_many_items(gb_cont1, single_key, 100);
725  if (!error) error = create_many_items(gb_cont2, mixed_keys, 20);
726  }
727  TEST_EXPECT_NO_ERROR(error);
728  }
729  ~TestDB() {
730  GB_close(gb_main);
731  }
732 };
733 
734 __ATTR__REDUCED_OPTIMIZE void TEST_DB_search() {
735  TestDB db;
736  TEST_EXPECT_NO_ERROR(db.error);
737 
738  {
739  GB_transaction ta(db.gb_main);
740 
741  TEST_EXPECT_EQUAL(GB_number_of_subentries(db.gb_cont1), 100);
742  TEST_EXPECT_EQUAL(GB_number_of_subentries(db.gb_cont2), 20);
743 
744  {
745  GBDATA *gb_any_child = GB_child(db.gb_cont1);
746  TEST_REJECT_NULL(gb_any_child);
747  TEST_EXPECT_EQUAL(gb_any_child, GB_entry(db.gb_cont1, "entry"));
748  TEST_EXPECT_EQUAL(gb_any_child, GB_search(db.gb_main, "container1/entry", GB_FIND));
749 
750  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_search(db.gb_main, "zic-zac", GB_FIND), "Invalid char '-' in key 'zic-zac'");
751 
752  // check (obsolete) link-syntax is invalid (@@@ remove these tests together with GB_OBSOLETE)
753  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_search(db.gb_main, "->entry", GB_FIND), "Invalid char '-' in key '->entry'");
754  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_search(db.gb_main, "entry->bla", GB_FIND), "Invalid char '-' in key 'entry->bla'");
755  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_search(db.gb_main, "container1/entry->nowhere", GB_FIND), "Invalid char '-' in key 'entry->nowhere'");
756  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_search(db.gb_main, "container1/nosuchentry->nowhere", GB_STRING), "Invalid char '-' in key 'nosuchentry->nowhere");
757  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_search(db.gb_main, "entry->", GB_FIND), "Invalid char '-' in key 'entry->'");
758  TEST_EXPECT_ERROR_CONTAINS(GB_check_hkey("->entry"), "Invalid character '-' in '->entry'");
759  TEST_EXPECT_ERROR_CONTAINS(GB_check_hkey("entry->"), "Invalid character '-' in 'entry->'");
760  TEST_EXPECT_ERROR_CONTAINS(GB_check_hkey("entry->bla"), "Invalid character '-' in 'entry->bla'");
761  TEST_EXPECT_ERROR_CONTAINS(GB_check_hkey("container1/entry->nowhere"), "Invalid character '-' in 'entry->nowhere'");
762  TEST_EXPECT_ERROR_CONTAINS(GB_check_hkey("container1/nosuchentry->nowhere"), "Invalid character '-' in 'nosuchentry->nowhere'");
763 
764  // check ..
765  TEST_EXPECT_EQUAL(GB_search(gb_any_child, "..", GB_FIND), db.gb_cont1);
766  TEST_EXPECT_EQUAL(GB_search(gb_any_child, "../..", GB_FIND), db.gb_main);
767  // above main entry
768  TEST_EXPECT_NORESULT__NOERROREXPORTED(GB_search(gb_any_child, "../../..", GB_FIND));
769  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_search(gb_any_child, "../../../impossible", GB_STRING), "cannot use '..' at root node");
770 
771  TEST_EXPECT_EQUAL(GB_search(gb_any_child, "", GB_FIND), gb_any_child); // return self
772  TEST_EXPECT_EQUAL(GB_search(gb_any_child, "/container1/", GB_FIND), db.gb_cont1); // accept trailing slash for container ..
773  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_search(gb_any_child, "/container1/entry/name/", GB_FIND), "terminal entry 'name' cannot be used as container"); // .. but not for normal entries
774 
775  TEST_EXPECT_EQUAL(GB_search(gb_any_child, "/", GB_FIND), db.gb_main);
776  TEST_EXPECT_EQUAL(GB_search(gb_any_child, "/container1/..", GB_FIND), db.gb_main);
777  TEST_EXPECT_NORESULT__NOERROREXPORTED(GB_search(gb_any_child, "/..", GB_FIND)); // main has no parent
778  }
779 
780  {
781  GBDATA *gb_child1 = GB_child(db.gb_cont2); TEST_REJECT_NULL(gb_child1);
782  GBDATA *gb_child2 = GB_nextChild(gb_child1); TEST_REJECT_NULL(gb_child2);
783  GBDATA *gb_child3 = GB_nextChild(gb_child2); TEST_REJECT_NULL(gb_child3);
784  GBDATA *gb_child4 = GB_nextChild(gb_child3); TEST_REJECT_NULL(gb_child4);
785 
786  TEST_EXPECT_EQUAL(GB_read_key_pntr(gb_child1), "item");
787  TEST_EXPECT_EQUAL(GB_read_key_pntr(gb_child2), "other");
788  TEST_EXPECT_EQUAL(GB_read_key_pntr(gb_child3), "item");
789  TEST_EXPECT_EQUAL(GB_read_key_pntr(gb_child4), "other");
790 
791  TEST_EXPECT_NORESULT__NOERROREXPORTED(GB_entry(db.gb_cont2, "entry"));
792  TEST_EXPECT_EQUAL(GB_entry(db.gb_cont2, "item"), gb_child1);
793  TEST_EXPECT_EQUAL(GB_entry(db.gb_cont2, "other"), gb_child2);
794 
795  TEST_EXPECT_EQUAL(GB_nextEntry(gb_child1), gb_child3);
796  TEST_EXPECT_EQUAL(GB_nextEntry(gb_child2), gb_child4);
797 
798  // check ..
799  TEST_EXPECT_EQUAL(GB_search(gb_child3, "../item", GB_FIND), gb_child1);
800  TEST_EXPECT_EQUAL(GB_search(gb_child3, "../other", GB_FIND), gb_child2);
801  TEST_EXPECT_EQUAL(GB_search(gb_child3, "../other/../item", GB_FIND), gb_child1);
802  }
803 
804  // ------------------------
805  // single entries
806 
807  {
808  GBDATA *gb_str = GB_searchOrCreate_string(db.gb_cont_misc, "str", "bla"); TEST_REJECT_NULL(gb_str);
809  GBDATA *gb_str_same = GB_searchOrCreate_string(db.gb_cont_misc, "str", "blub");
810 
811  TEST_EXPECT_EQUAL(gb_str, gb_str_same);
812  TEST_EXPECT_EQUAL(GB_read_char_pntr(gb_str), "bla");
813 
814  GBDATA *gb_int = GB_searchOrCreate_int(db.gb_cont_misc, "int", 4711); TEST_REJECT_NULL(gb_int);
815  GBDATA *gb_int_same = GB_searchOrCreate_int(db.gb_cont_misc, "int", 2012);
816 
817  TEST_EXPECT_EQUAL(gb_int, gb_int_same);
818  TEST_EXPECT_EQUAL(GB_read_int(gb_int), 4711);
819 
820  GBDATA *gb_float = GB_searchOrCreate_float(db.gb_cont_misc, "float", 0.815); TEST_REJECT_NULL(gb_float);
821  GBDATA *gb_float_same = GB_searchOrCreate_float(db.gb_cont_misc, "float", 3.1415);
822 
823  TEST_EXPECT_EQUAL(gb_float, gb_float_same);
824  TEST_EXPECT_SIMILAR(GB_read_float(gb_float), 0.815, 0.0001);
825 
826  TEST_EXPECT_EQUAL (GB_read_char_pntr(GB_searchOrCreate_string(db.gb_cont_misc, "sub1/str", "blub")), "blub");
827  TEST_EXPECT_EQUAL (GB_read_int (GB_searchOrCreate_int (db.gb_cont_misc, "sub2/int", 2012)), 2012);
828  TEST_EXPECT_SIMILAR(GB_read_float (GB_searchOrCreate_float (db.gb_cont_misc, "sub3/float", 3.1415)), 3.1415, 0.00001);
829 
830  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_searchOrCreate_float (db.gb_cont_misc, "int", 0.815), "has wrong type");
831  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_searchOrCreate_float (db.gb_cont_misc, "str", 0.815), "has wrong type");
832  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_searchOrCreate_int (db.gb_cont_misc, "float", 4711), "has wrong type");
833  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_searchOrCreate_int (db.gb_cont_misc, "str", 4711), "has wrong type");
834  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_searchOrCreate_string(db.gb_cont_misc, "float", "bla"), "has wrong type");
835  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_searchOrCreate_string(db.gb_cont_misc, "int", "bla"), "has wrong type");
836 
837  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_searchOrCreate_string(db.gb_cont_misc, "*", "bla"), "Invalid char '*' in key '*'");
838  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_searchOrCreate_string(db.gb_cont_misc, "int*", "bla"), "Invalid char '*' in key 'int*'");
839  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_searchOrCreate_string(db.gb_cont_misc, "sth_else*", "bla"), "Invalid char '*' in key 'sth_else*'");
840 
841  GBDATA *gb_entry;
842  TEST_EXPECT_NORESULT__NOERROREXPORTED(GB_search(db.gb_cont_misc, "subcont/entry", GB_FIND));
843  TEST_EXPECT_RESULT__NOERROREXPORTED(gb_entry = GB_search(db.gb_cont_misc, "subcont/entry", GB_INT));
844  TEST_EXPECT_EQUAL(GB_read_int(gb_entry), 0);
845 
846  GBDATA *gb_cont1;
847  TEST_EXPECT_RESULT__NOERROREXPORTED(gb_cont1 = GB_search(db.gb_cont_misc, "subcont", GB_CREATE_CONTAINER));
848  TEST_EXPECT_EQUAL(GB_child(gb_cont1), gb_entry); // test GB_search found the container created implicitely above
849 
850  GBDATA *gb_cont2;
851  TEST_EXPECT_RESULT__NOERROREXPORTED(gb_cont2 = GB_search(db.gb_cont_misc, "subcont2", GB_CREATE_CONTAINER)); // create new container
852 
853  // -----------------------
854  // search values
855 
856  GBDATA *gb_4711;
857  TEST_EXPECT_RESULT__NOERROREXPORTED(gb_4711 = GB_find_int(db.gb_cont_misc, "int", 4711, SEARCH_CHILD));
858  TEST_EXPECT_EQUAL(gb_4711, gb_int);
859 
860  TEST_EXPECT_NULL(GB_find_int(db.gb_cont_misc, "int", 2012, SEARCH_CHILD));
861 
862  GBDATA *gb_bla;
863  TEST_EXPECT_RESULT__NOERROREXPORTED(gb_bla = GB_find_string(db.gb_cont_misc, "str", "bla", GB_MIND_CASE, SEARCH_CHILD));
864  TEST_EXPECT_EQUAL(gb_bla, gb_str);
865  TEST_EXPECT_RESULT__NOERROREXPORTED(gb_bla = GB_find_string(gb_4711, "str", "bla", GB_MIND_CASE, SEARCH_BROTHER));
866  TEST_EXPECT_EQUAL(gb_bla, gb_str);
867 
868  TEST_EXPECT_NULL(GB_find_string(db.gb_cont_misc, "str", "blub", GB_MIND_CASE, SEARCH_CHILD));
869 
870  GBDATA *gb_name;
871  TEST_REJECT_NULL (GB_find_string (db.gb_cont1, "name", "entry 77", GB_MIND_CASE, SEARCH_GRANDCHILD));
872  TEST_REJECT_NULL (GB_find_string (db.gb_cont1, "name", "entry 99", GB_MIND_CASE, SEARCH_GRANDCHILD));
873  TEST_EXPECT_NORESULT__NOERROREXPORTED(GB_find_string (db.gb_cont1, "name", "entry 100", GB_MIND_CASE, SEARCH_GRANDCHILD));
874  TEST_EXPECT_NORESULT__NOERROREXPORTED(GB_find_string (db.gb_cont1, "name", "ENTRY 13", GB_MIND_CASE, SEARCH_GRANDCHILD));
875  TEST_REJECT_NULL (gb_name = GB_find_string(db.gb_cont1, "name", "ENTRY 13", GB_IGNORE_CASE, SEARCH_GRANDCHILD));
876 
877  GBDATA *gb_sub;
878  TEST_REJECT_NULL(gb_sub = GB_get_father(gb_name)); TEST_EXPECT_EQUAL(GBT_get_name(gb_sub), "entry 13");
879  TEST_REJECT_NULL(gb_sub = GB_followingEntry(gb_sub, 0)); TEST_EXPECT_EQUAL(GBT_get_name(gb_sub), "entry 14");
880  TEST_REJECT_NULL(gb_sub = GB_followingEntry(gb_sub, 1)); TEST_EXPECT_EQUAL(GBT_get_name(gb_sub), "entry 16");
881  TEST_REJECT_NULL(gb_sub = GB_followingEntry(gb_sub, 10)); TEST_EXPECT_EQUAL(GBT_get_name(gb_sub), "entry 27");
882  TEST_EXPECT_NORESULT__NOERROREXPORTED(GB_followingEntry(gb_sub, -1U));
883  TEST_REJECT_NULL(gb_sub = GB_brother(gb_sub, "entry")); TEST_EXPECT_EQUAL(GBT_get_name(gb_sub), "entry 0");
884 
885  TEST_EXPECT_EQUAL(gb_bla = GB_search(gb_cont1, "/misc/str", GB_FIND), gb_str); // fullpath (ignores passed GBDATA)
886 
887  // keyless search
888  TEST_EXPECT_NORESULT__NOERROREXPORTED(GB_search(db.gb_cont_misc, NULp, GB_FIND));
889 
890  // ----------------------------
891  // GB_get_GBDATA_path
892 
893  TEST_EXPECT_EQUAL(GB_get_GBDATA_path(gb_int), "/main/misc/int");
894  TEST_EXPECT_EQUAL(GB_get_GBDATA_path(gb_str), "/main/misc/str");
895  TEST_EXPECT_EQUAL(GB_get_GBDATA_path(gb_entry), "/main/misc/subcont/entry");
896  TEST_EXPECT_EQUAL(GB_get_GBDATA_path(gb_cont2), "/main/misc/subcont2");
897 
898  // -----------------------------------------
899  // search/create with changed type
900 
901  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_search(db.gb_cont_misc, "str", GB_INT), "Inconsistent type for field");
902  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_search(db.gb_cont_misc, "subcont", GB_STRING), "Inconsistent type for field");
903 
904  // ---------------------------------------------
905  // search containers with trailing '/'
906 
907  GBDATA *gb_cont2_slash;
908  TEST_EXPECT_RESULT__NOERROREXPORTED(gb_cont2_slash = GB_search(db.gb_cont_misc, "subcont2/", GB_FIND));
909  TEST_EXPECT_EQUAL(gb_cont2_slash, gb_cont2);
910 
911  GBDATA *gb_rootcont;
912  GBDATA *gb_rootcont_slash;
913  TEST_EXPECT_RESULT__NOERROREXPORTED(gb_rootcont = GB_search(db.gb_main, "/container1", GB_FIND));
914  TEST_EXPECT_RESULT__NOERROREXPORTED(gb_rootcont_slash = GB_search(db.gb_main, "/container1/", GB_FIND));
915  TEST_EXPECT_EQUAL(gb_rootcont_slash, gb_rootcont);
916  }
917 
918  {
919  // check invalid searches
920  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_search(db.gb_cont_misc, "sub/inva*lid", GB_INT), "Invalid char '*' in key 'inva*lid'");
921  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_search(db.gb_cont_misc, "sub/1 3", GB_INT), "Invalid char ' ' in key '1 3'");
922  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_search(db.gb_cont_misc, "sub//sub", GB_INT), "Invalid '//' in key 'sub//sub'");
923  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_search(db.gb_cont_misc, "subcont2//", GB_FIND), "Invalid '//' in key 'subcont2//'");
924  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_search(db.gb_cont_misc, "sub/..sub", GB_INT), "Expected '/' after '..' in key '..sub'");
925  TEST_EXPECT_NORESULT__ERROREXPORTED_CONTAINS(GB_search(db.gb_cont_misc, "subcont/entry/", GB_FIND), "terminal entry 'entry' cannot be used as container");
926  }
927 
928  // ---------------
929  // marks
930 
933 
934  TEST_EXPECT_NORESULT__NOERROREXPORTED(GB_first_marked(db.gb_cont2, "entry"));
935 
936  GBDATA *gb_marked;
937  TEST_REJECT_NULL(gb_marked = GB_first_marked(db.gb_cont2, "item"));
938  TEST_EXPECT_EQUAL(GBT_get_name(gb_marked), "item 0");
939 
940  TEST_EXPECT_NORESULT__NOERROREXPORTED(GB_following_marked(gb_marked, "item", 1)); // skip over last
941 
942  TEST_REJECT_NULL(gb_marked = GB_next_marked(gb_marked, "item")); // find last
943  TEST_EXPECT_EQUAL(GBT_get_name(gb_marked), "item 14");
944  }
945 
946  // @@@ delete some species, then search again
947 
948  TEST_EXPECT_NO_ERROR(db.error);
949 }
950 
951 
952 #endif // UNIT_TESTS
GBDATA * GB_entry(GBDATA *father, const char *key)
Definition: adquery.cxx:334
GBDATA * GB_child(GBDATA *father)
Definition: adquery.cxx:322
const char * GB_ERROR
Definition: arb_core.h:25
string result
GBDATA * GB_open(const char *path, const char *opent)
Definition: ad_load.cxx:1363
GB_TYPES type
static const char * GB_get_GBDATA_path(GBDATA *gbd)
Definition: adquery.cxx:44
GBDATA * GB_find(GBDATA *gbd, const char *key, GB_SEARCH_TYPE gbs)
Definition: adquery.cxx:295
#define TEST_EXPECT_SIMILAR(expr, want, epsilon)
Definition: test_unit.h:1287
long GB_read_int(GBDATA *gbd)
Definition: arbdb.cxx:699
__ATTR__USERESULT GB_ERROR send_update_to_server(GBDATA *gbd) __ATTR__USERESULT
Definition: arbdb.cxx:2432
GB_ERROR GB_write_string(GBDATA *gbd, const char *s)
Definition: arbdb.cxx:1361
gb_flag_types2 flags2
Definition: gb_data.h:135
GBCONTAINER * expect_container() const
Definition: gb_data.h:169
GBDATA * find_or_create(GBCONTAINER *gb_parent, const char *key, GB_TYPES create, bool internflag)
Definition: adquery.cxx:420
gb_user * users[GB_MAX_USERS]
Definition: gb_main.h:156
unsigned int folded_container
Definition: gb_data.h:82
GBDATA * gb_index_find(GBCONTAINER *gbf, gb_index_files *ifs, GBQUARK quark, const char *val, GB_CASE case_sens, int after_index)
Definition: adindex.cxx:267
static void build_GBDATA_path(GBDATA *gbd, char **buffer)
Definition: adquery.cxx:26
static GBDATA * find_sub_sub_by_quark(GBCONTAINER *const father, const char *key, GBQUARK sub_key_quark, GB_TYPES type, const char *val, GB_CASE case_sens, GBDATA *after)
Definition: adquery.cxx:182
GBCONTAINER * gb_create_container(GBCONTAINER *father, const char *key)
Definition: arbdb.cxx:1747
void GB_internal_errorf(const char *templat,...)
Definition: arb_msg.cxx:458
const char * GBS_global_string(const char *templat,...)
Definition: arb_msg.cxx:204
GBDATA * GB_nextEntry(GBDATA *entry)
Definition: adquery.cxx:339
bool GB_have_error()
Definition: arb_msg.cxx:349
GBDATA * GB_HEADER_LIST_GBD(gb_header_list &hl)
Definition: gb_header.h:42
static GBDATA * gb_search_marked(GBCONTAINER *gbc, GBQUARK key_quark, int firstindex, size_t skip_over)
Definition: adquery.cxx:613
CONSTEXPR_INLINE gb_header_list * GB_DATA_LIST_HEADER(gb_data_list &dl)
Definition: gb_data.h:105
gb_header_flags & GB_ARRAY_FLAGS(GBDATA *gbd)
Definition: gb_header.h:49
GBDATA * GB_find_sub_by_quark(GBDATA *father, GBQUARK key_quark, GBDATA *after, size_t skip_over)
Definition: adquery.cxx:174
gb_index_files * GB_INDEX_FILES_NEXT(gb_index_files *ixf)
Definition: gb_index.h:87
GB_TYPES type() const
Definition: gb_data.h:139
GB_MAIN_TYPE * GBCONTAINER_MAIN(GBCONTAINER *gbc)
Definition: gb_data.h:289
GBDATA * GB_searchOrCreate_float(GBDATA *gb_container, const char *fieldpath, float default_value)
Definition: adquery.cxx:591
char buffer[MESSAGE_BUFFERSIZE]
Definition: seq_search.cxx:34
GBDATA * GB_get_father(GBDATA *gbd)
Definition: arbdb.cxx:1696
#define NOT4PERL
Definition: arbdb_base.h:23
GBENTRY * gb_create(GBCONTAINER *father, const char *key, GB_TYPES type)
Definition: arbdb.cxx:1737
POS_TREE1 * father
Definition: probe_tree.h:39
GB_ERROR GB_check_hkey(const char *key) __ATTR__USERESULT
Definition: adstring.cxx:92
GBDATA * GBCMC_find(GBDATA *gbd, const char *key, GB_TYPES type, const char *str, GB_CASE case_sens, GB_SEARCH_TYPE gbs)
Definition: adcomm.cxx:1725
GB_ERROR GB_export_error(const char *error)
Definition: arb_msg.cxx:259
uchar flags
Definition: probe_tree.h:38
GB_ERROR GB_await_error()
Definition: arb_msg.cxx:353
AliDataPtr after(AliDataPtr data, size_t pos)
Definition: insdel.cxx:593
GB_ERROR gb_unfold(GBCONTAINER *gbc, long deep, int index_pos)
Definition: arbdb.cxx:556
GBDATA * GB_create_container(GBDATA *father, const char *key)
Definition: arbdb.cxx:1803
Definition: arbdb.h:67
GBDATA * GB_searchOrCreate_string(GBDATA *gb_container, const char *fieldpath, const char *default_value)
Definition: adquery.cxx:546
TYPE * ARB_alloc(size_t nelem)
Definition: arb_mem.h:56
GB_CSTR GB_read_key_pntr(GBDATA *gbd)
Definition: arbdb.cxx:1630
GBDATA * GB_create(GBDATA *father, const char *key, GB_TYPES type)
Definition: arbdb.cxx:1755
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)
Definition: adquery.cxx:178
GBDATA * GB_brother(GBDATA *entry, const char *key)
Definition: adquery.cxx:361
long GB_number_of_subentries(GBDATA *gbd)
Definition: arbdb.cxx:2856
GBDATA * GB_search(GBDATA *gbd, const char *fieldpath, GB_TYPES create)
Definition: adquery.cxx:531
GBDATA * GB_find_string(GBDATA *gbd, const char *key, const char *str, GB_CASE case_sens, GB_SEARCH_TYPE gbs)
Definition: adquery.cxx:302
bool is_a_string() const
Definition: gb_data.h:144
void GB_clear_error()
Definition: arb_msg.cxx:365
static bool gb_find_value_equal(GBDATA *gb, GB_TYPES type, const char *val, GB_CASE case_sens)
Definition: adquery.cxx:60
unsigned int key_quark
Definition: gb_header.h:21
bool is_container() const
Definition: gb_data.h:147
#define TEST_REJECT_NULL(n)
Definition: test_unit.h:1309
static void error(const char *msg)
Definition: mkptypes.cxx:96
static keychar_table keychars
Definition: adquery.cxx:414
bool is_client() const
Definition: gb_main.h:204
GBDATA * gb_find_by_nr(GBCONTAINER *father, int index)
Definition: adquery.cxx:367
GBQUARK key
Definition: gb_index.h:49
char * str
Definition: defines.h:20
GBDATA * GB_followingEntry(GBDATA *entry, size_t skip_over)
Definition: adquery.cxx:344
unsigned int update_in_server
Definition: gb_data.h:83
float GB_read_float(GBDATA *gbd)
Definition: arbdb.cxx:714
GBCONTAINER * as_container() const
Definition: gb_data.h:155
#define BUFFERSIZE
Definition: adquery.cxx:42
GB_write_int const char GB_write_autoconv_string WRITE_SKELETON(write_pointer, GBDATA *,"%p", GB_write_pointer) char *AW_awa if)(!gb_var) return strdup("")
Definition: AW_awar.cxx:166
GBQUARK GB_get_quark(GBDATA *gbd)
Definition: arbdb.cxx:1677
GBDATA * GB_following_marked(GBDATA *gbd, const char *keystring, size_t skip_over)
Definition: adquery.cxx:663
CONSTEXPR_INLINE GBCONTAINER * GB_FATHER(GBDATA *gbd)
Definition: gb_data.h:271
GB_SEARCH_TYPE
Definition: arbdb.h:99
Definition: arbdb.h:86
gb_index_files * GBCONTAINER_IFS(GBCONTAINER *gbc)
Definition: gb_index.h:94
GB_ERROR GB_write_float(GBDATA *gbd, float f)
Definition: arbdb.cxx:1255
GB_CASE
Definition: arb_core.h:30
const int GB_MAX_LOCAL_SEARCH
Definition: adtune.cxx:26
GB_ERROR GB_write_int(GBDATA *gbd, long i)
Definition: arbdb.cxx:1220
const char * GB_first_non_key_char(const char *str)
Definition: adquery.cxx:416
#define __ATTR__REDUCED_OPTIMIZE
Definition: test_unit.h:83
void GB_test_transaction(GB_MAIN_TYPE *Main)
Definition: gb_ta.h:21
const char * first_non_key_character(const char *str) const
Definition: adquery.cxx:402
Definition: arbdb.h:63
GB_ERROR GB_export_errorf(const char *templat,...)
Definition: arb_msg.cxx:264
void GB_internal_error(const char *message)
Definition: arb_msg.cxx:435
#define TEST_EXPECT_NULL(n)
Definition: test_unit.h:1307
#define gb_assert(cond)
Definition: arbdbt.h:11
void GB_write_flag(GBDATA *gbd, long flag)
Definition: arbdb.cxx:2737
int userbit
Definition: gb_comm.h:24
#define assert_or_exit(cond)
Definition: arb_assert.h:263
long index
Definition: gb_data.h:133
GBQUARK GB_find_existing_quark(GBDATA *gbd, const char *key)
Definition: arbdb.cxx:1664
static GBDATA * gb_expect_type(GBDATA *gbd, GB_TYPES expected_type, const char *fieldname)
Definition: adquery.cxx:535
static GBDATA * gb_find_internal(GBDATA *gbd, const char *key, GB_TYPES type, const char *val, GB_CASE case_sens, GB_SEARCH_TYPE gbs)
Definition: adquery.cxx:250
unsigned int changed
Definition: gb_header.h:22
GBDATA * GB_nextChild(GBDATA *child)
Definition: adquery.cxx:326
#define TEST_EXPECT_NO_ERROR(call)
Definition: test_unit.h:1107
NOT4PERL GBDATA * GB_find_int(GBDATA *gbd, const char *key, long val, GB_SEARCH_TYPE gbs)
Definition: adquery.cxx:311
GBDATA * GB_first_marked(GBDATA *gbd, const char *keystring)
Definition: adquery.cxx:655
GBDATA * GB_next_marked(GBDATA *gbd, const char *keystring)
Definition: adquery.cxx:670
long GB_number_of_marked_subentries(GBDATA *gbd)
Definition: adquery.cxx:635
#define NULp
Definition: cxxforward.h:97
gb_data_list d
Definition: gb_data.h:246
#define TEST_EXPECT_ERROR_CONTAINS(call, part)
Definition: test_unit.h:1103
static GBDATA * find_sub_by_quark(GBCONTAINER *father, GBQUARK key_quark, GB_TYPES type, const char *val, GB_CASE case_sens, GBDATA *after, size_t skip_over)
Definition: adquery.cxx:94
gb_header_flags flags
Definition: gb_header.h:35
GBDATA * gb_search(GBCONTAINER *gbc, const char *key, GB_TYPES create, int internflag)
Definition: adquery.cxx:445
const char * GBT_get_name(GBDATA *gb_item)
Definition: aditem.cxx:446
GBDATA * GB_searchOrCreate_int(GBDATA *gb_container, const char *fieldpath, long default_value)
Definition: adquery.cxx:569
GB_TYPES
Definition: arbdb.h:62
#define FALLTHROUGH
Definition: cxxforward.h:107
GB_transaction ta(gb_var)
GB_CSTR GB_read_char_pntr(GBDATA *gbd)
Definition: arbdb.cxx:874
GBDATA * gb_main
Definition: adname.cxx:33
bool GBS_string_matches(const char *str, const char *expr, GB_CASE case_sens)
Definition: admatch.cxx:193
const char * GB_KEY(GBDATA *gbd)
Definition: gb_key.h:49
int nheader
Definition: gb_data.h:102
size_t GB_countEntries(GBDATA *father, const char *key)
Definition: adquery.cxx:351
GBCONTAINER * gb_get_root(GBENTRY *gbe)
Definition: arbdb.cxx:1715
int GBQUARK
Definition: arbdb_base.h:30
#define TEST_EXPECT_EQUAL(expr, want)
Definition: test_unit.h:1283
GBCONTAINER * get_father()
Definition: gb_data.h:276
void GB_close(GBDATA *gbd)
Definition: arbdb.cxx:625
static Score ** U
Definition: align.cxx:67
Definition: arbdb.h:66