root/trunk/ARBDB/arbdb.cxx

Revision 8664, 84.9 KB (checked in by westram, 4 weeks ago)
  • patch for OSX
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : arbdb.cxx                                         //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#if defined(DARWIN)
12#include <cstdio>
13#endif // DARWIN
14
15#include <rpc/types.h>
16#include <rpc/xdr.h>
17
18#include "gb_cb.h"
19#include "gb_comm.h"
20#include "gb_compress.h"
21#include "gb_localdata.h"
22#include "gb_ta.h"
23#include "gb_ts.h"
24
25
26gb_local_data *gb_local = 0;
27
28#ifdef ARBDB_SIZEDEBUG
29long *arbdb_stat;
30#endif
31
32#define INIT_TYPE_NAME(t) GB_TYPES_name[t] = #t
33
34static const char *GB_TYPES_2_name(GB_TYPES type) {
35    static const char *GB_TYPES_name[GB_TYPE_MAX];
36    static bool        initialized = false;
37
38    if (!initialized) {
39        memset(GB_TYPES_name, 0, sizeof(GB_TYPES_name));
40        INIT_TYPE_NAME(GB_NONE);
41        INIT_TYPE_NAME(GB_BIT);
42        INIT_TYPE_NAME(GB_BYTE);
43        INIT_TYPE_NAME(GB_INT);
44        INIT_TYPE_NAME(GB_FLOAT);
45        INIT_TYPE_NAME(GB_POINTER);
46        INIT_TYPE_NAME(GB_BITS);
47        INIT_TYPE_NAME(GB_BYTES);
48        INIT_TYPE_NAME(GB_INTS);
49        INIT_TYPE_NAME(GB_FLOATS);
50        INIT_TYPE_NAME(GB_LINK);
51        INIT_TYPE_NAME(GB_STRING);
52        INIT_TYPE_NAME(GB_STRING_SHRT);
53        INIT_TYPE_NAME(GB_DB);
54        initialized = true;
55    }
56
57    const char *name = NULL;
58    if (type >= 0 && type<GB_TYPE_MAX) name = GB_TYPES_name[type];
59    if (!name) name = GBS_global_string("invalid-type-%i", type);
60    return name;
61}
62
63inline GB_ERROR gb_transactable_type(GB_TYPES type, GBDATA *gbd) {
64    GB_ERROR error = NULL;
65    if (!GB_MAIN(gbd)->transaction) {
66        error = "No running transaction";
67    }
68    else if (GB_ARRAY_FLAGS(gbd).changed == GB_DELETED) {
69        error = "Entry has been deleted";
70    }
71    else {
72        GB_TYPES gb_type = GB_TYPE(gbd);
73        if (gb_type != type && (type != GB_STRING || GB_TYPE(gbd) != GB_LINK)) {
74            char *rtype    = strdup(GB_TYPES_2_name(type));
75            char *rgb_type = strdup(GB_TYPES_2_name(gb_type));
76           
77            error = GBS_global_string("type mismatch (want='%s', got='%s') in '%s'", rtype, rgb_type, GB_get_db_path(gbd));
78
79            free(rgb_type);
80            free(rtype);
81        }
82    }
83    if (error) {
84        GBK_dump_backtrace(stderr, error); // it's a bug: none of the above errors should ever happen
85        gb_assert(0);
86    }
87    return error;
88}
89
90__ATTR__USERESULT static GB_ERROR gb_security_error(GBDATA *gbd) {
91    GB_MAIN_TYPE *Main  = GB_MAIN(gbd);
92    const char   *error = GBS_global_string("Protection: Attempt to change a level-%i-'%s'-entry,\n"
93                                            "but your current security level is only %i",
94                                            GB_GET_SECURITY_WRITE(gbd),
95                                            GB_read_key_pntr(gbd),
96                                            Main->security_level);
97#if defined(DEBUG)
98    fprintf(stderr, "%s\n", error);
99#endif // DEBUG
100    return error;
101}
102
103inline GB_ERROR gb_type_writeable_to(GB_TYPES type, GBDATA *gbd) {
104    GB_ERROR error = gb_transactable_type(type, gbd);
105    if (!error) {
106        if (GB_GET_SECURITY_WRITE(gbd) > GB_MAIN(gbd)->security_level) {
107            error = gb_security_error(gbd);
108        }
109    }
110    return error;
111}
112inline GB_ERROR gb_type_readable_from(GB_TYPES type, GBDATA *gbd) {
113    return gb_transactable_type(type, gbd);
114}
115
116inline GB_ERROR error_with_dbentry(const char *action, GBDATA *gbd, GB_ERROR error) {
117    const char *path = GB_get_db_path(gbd);
118    return GBS_global_string("Can't %s '%s':\n%s", action, path, error);
119}
120
121
122#define RETURN_ERROR_IF_NOT_WRITEABLE_AS_TYPE(gbd, type)        \
123    do {                                                        \
124        GB_ERROR error = gb_type_writeable_to(type, gbd);       \
125        if (error) {                                            \
126            return error_with_dbentry("write", gbd, error);     \
127        }                                                       \
128    } while(0)
129
130#define EXPORT_ERROR_AND_RETURN_0_IF_NOT_READABLE_AS_TYPE(gbd, type)    \
131    do {                                                                \
132        GB_ERROR error = gb_type_readable_from(type, gbd);              \
133        if (error) {                                                    \
134            error = error_with_dbentry("read", gbd, error);             \
135            GB_export_error(error);                                     \
136            return 0;                                                   \
137        }                                                               \
138    } while(0)                                                          \
139
140
141#if defined(WARN_TODO)
142#warning replace GB_TEST_READ / GB_TEST_READ by new names later
143#endif
144
145#define GB_TEST_READ(gbd, type, ignored) EXPORT_ERROR_AND_RETURN_0_IF_NOT_READABLE_AS_TYPE(gbd, type)
146#define GB_TEST_WRITE(gbd, type, ignored) RETURN_ERROR_IF_NOT_WRITEABLE_AS_TYPE(gbd, type)
147
148#define GB_TEST_NON_BUFFER(x, gerror)                                   \
149    do {                                                                \
150        if (GB_is_in_buffer(x)) {                                       \
151            GBK_terminatef("%s: you are not allowed to write any data, which you get by pntr", gerror); \
152        }                                                               \
153    } while (0)
154
155
156static GB_ERROR GB_safe_atof(const char *str, double *res) {
157    GB_ERROR  error = NULL;
158    char     *end;
159    *res            = strtod(str, &end);
160    if (end == str || end[0] != 0) {
161        if (!str[0]) {
162            *res = 0.0;
163        }
164        else {
165            error = GBS_global_string("cannot convert '%s' to double", str);
166        }
167    }
168    return error;
169}
170
171double GB_atof(const char *str) {
172    // convert ASCII to double
173    double res = 0;
174    ASSERT_NO_ERROR(GB_safe_atof(str, &res)); // expected double in 'str'- better use GB_safe_atof()
175    return res;
176}
177
178// ---------------------------
179//      compression tables
180
181const int gb_convert_type_2_compression_flags[] = {
182    GB_COMPRESSION_NONE,                                                                 // GB_NONE  0
183    GB_COMPRESSION_NONE,                                                                 // GB_BIT   1
184    GB_COMPRESSION_NONE,                                                                 // GB_BYTE  2
185    GB_COMPRESSION_NONE,                                                                 // GB_INT   3
186    GB_COMPRESSION_NONE,                                                                 // GB_FLOAT 4
187    GB_COMPRESSION_NONE,                                                                 // GB_??    5
188    GB_COMPRESSION_BITS,                                                                 // GB_BITS  6
189    GB_COMPRESSION_NONE,                                                                 // GB_??    7
190    GB_COMPRESSION_RUNLENGTH | GB_COMPRESSION_HUFFMANN,                                  // GB_BYTES 8
191    GB_COMPRESSION_RUNLENGTH | GB_COMPRESSION_HUFFMANN | GB_COMPRESSION_SORTBYTES,       // GB_INTS  9
192    GB_COMPRESSION_RUNLENGTH | GB_COMPRESSION_HUFFMANN | GB_COMPRESSION_SORTBYTES,       // GB_FLTS 10
193    GB_COMPRESSION_NONE,                                                                 // GB_LINK 11
194    GB_COMPRESSION_RUNLENGTH | GB_COMPRESSION_HUFFMANN | GB_COMPRESSION_DICTIONARY,      // GB_STR  12
195    GB_COMPRESSION_NONE,                                                                 // GB_STRS 13
196    GB_COMPRESSION_NONE,                                                                 // GB??    14
197    GB_COMPRESSION_NONE                                                                  // GB_DB   15
198};
199
200int gb_convert_type_2_sizeof[] = { /* contains the unit-size of data stored in DB,
201                                    * i.e. realsize = unit_size * GB_GETSIZE()
202                                    */
203    0,                                              // GB_NONE  0
204    0,                                              // GB_BIT   1
205    sizeof(char),                                   // GB_BYTE  2
206    sizeof(int),                                    // GB_INT   3
207    sizeof(float),                                  // GB_FLOAT 4
208    0,                                              // GB_??    5
209    0,                                              // GB_BITS  6
210    0,                                              // GB_??    7
211    sizeof(char),                                   // GB_BYTES 8
212    sizeof(int),                                    // GB_INTS  9
213    sizeof(float),                                  // GB_FLTS 10
214    sizeof(char),                                   // GB_LINK 11
215    sizeof(char),                                   // GB_STR  12
216    sizeof(char),                                   // GB_STRS 13
217    0,                                              // GB_??   14
218    0,                                              // GB_DB   15
219};
220
221int gb_convert_type_2_appendix_size[] = { /* contains the size of the suffix (aka terminator element)
222                                           * size is in bytes
223                                           */
224
225    0,                                              // GB_NONE  0
226    0,                                              // GB_BIT   1
227    0,                                              // GB_BYTE  2
228    0,                                              // GB_INT   3
229    0,                                              // GB_FLOAT 4
230    0,                                              // GB_??    5
231    0,                                              // GB_BITS  6
232    0,                                              // GB_??    7
233    0,                                              // GB_BYTES 8
234    0,                                              // GB_INTS  9
235    0,                                              // GB_FLTS 10
236    1,                                              // GB_LINK 11 (zero terminated)
237    1,                                              // GB_STR  12 (zero terminated)
238    1,                                              // GB_STRS 13 (zero terminated)
239    0,                                              // GB_??   14
240    0,                                              // GB_DB   15
241};
242
243
244// ---------------------------------
245//      local buffer management
246
247static void init_buffer(gb_buffer *buf, size_t initial_size) {
248    buf->size = initial_size;
249    buf->mem  = buf->size ? (char*)malloc(buf->size) : NULL;
250}
251
252static char *check_out_buffer(gb_buffer *buf) {
253    char *checkOut = buf->mem;
254
255    buf->mem  = 0;
256    buf->size = 0;
257
258    return checkOut;
259}
260
261static void alloc_buffer(gb_buffer *buf, size_t size) {
262    free(buf->mem);
263    buf->size = size;
264#if (MEMORY_TEST==1)
265    buf->mem  = (char *)malloc(buf->size);
266#else
267    buf->mem  = (char *)GB_calloc(buf->size, 1);
268#endif
269}
270
271static GB_BUFFER give_buffer(gb_buffer *buf, size_t size) {
272#if (MEMORY_TEST==1)
273    alloc_buffer(buf, size); // do NOT reuse buffer if testing memory
274#else
275    if (size >= buf->size) {
276        alloc_buffer(buf, size);
277    }
278#endif
279    return buf->mem;
280}
281
282static int is_in_buffer(gb_buffer *buf, GB_CBUFFER ptr) {
283    return ptr >= buf->mem && ptr < buf->mem+buf->size;
284}
285
286// ------------------------------
287
288GB_BUFFER GB_give_buffer(size_t size) {
289    // return a pointer to a static piece of memory at least size bytes long
290    return give_buffer(&gb_local->buf1, size);
291}
292
293GB_BUFFER GB_increase_buffer(size_t size) {
294    if (size < gb_local->buf1.size) {
295        char   *old_buffer = gb_local->buf1.mem;
296        size_t  old_size   = gb_local->buf1.size;
297
298        gb_local->buf1.mem = NULL;
299        alloc_buffer(&gb_local->buf1, size);
300        memcpy(gb_local->buf1.mem, old_buffer, old_size);
301
302        free(old_buffer);
303    }
304    return gb_local->buf1.mem;
305}
306
307NOT4PERL int GB_give_buffer_size() {
308    return gb_local->buf1.size;
309}
310
311GB_BUFFER GB_give_buffer2(long size) {
312    return give_buffer(&gb_local->buf2, size);
313}
314
315static int GB_is_in_buffer(GB_CBUFFER ptr) {
316    /* returns 1 or 2 if 'ptr' points to gb_local->buf1/buf2
317     * returns 0 otherwise
318     */
319    int buffer = 0;
320
321    if (is_in_buffer(&gb_local->buf1, ptr)) buffer = 1;
322    else if (is_in_buffer(&gb_local->buf2, ptr)) buffer = 2;
323
324    return buffer;
325}
326
327char *GB_check_out_buffer(GB_CBUFFER buffer) {
328    /* Check a piece of memory out of the buffer management
329     * after it is checked out, the user has the full control to use and free it
330     * Returns a pointer to the start of the buffer (even if 'buffer' points inside the buffer!)
331     */
332    char *old = 0;
333
334    if (is_in_buffer(&gb_local->buf1, buffer)) old = check_out_buffer(&gb_local->buf1);
335    else if (is_in_buffer(&gb_local->buf2, buffer)) old = check_out_buffer(&gb_local->buf2);
336
337    return old;
338}
339
340GB_BUFFER GB_give_other_buffer(GB_CBUFFER buffer, long size) {
341    return is_in_buffer(&gb_local->buf1, buffer)
342        ? GB_give_buffer2(size)
343        : GB_give_buffer(size);
344}
345
346static unsigned char GB_BIT_compress_data[] = {
347    0x1d, GB_CS_OK,  0, 0,
348    0x04, GB_CS_OK,  0, 1,
349    0x0a, GB_CS_OK,  0, 2,
350    0x0b, GB_CS_OK,  0, 3,
351    0x0c, GB_CS_OK,  0, 4,
352    0x1a, GB_CS_OK,  0, 5,
353    0x1b, GB_CS_OK,  0, 6,
354    0x1c, GB_CS_OK,  0, 7,
355    0xf0, GB_CS_OK,  0, 8,
356    0xf1, GB_CS_OK,  0, 9,
357    0xf2, GB_CS_OK,  0, 10,
358    0xf3, GB_CS_OK,  0, 11,
359    0xf4, GB_CS_OK,  0, 12,
360    0xf5, GB_CS_OK,  0, 13,
361    0xf6, GB_CS_OK,  0, 14,
362    0xf7, GB_CS_OK,  0, 15,
363    0xf8, GB_CS_SUB, 0, 16,
364    0xf9, GB_CS_SUB, 0, 32,
365    0xfa, GB_CS_SUB, 0, 48,
366    0xfb, GB_CS_SUB, 0, 64,
367    0xfc, GB_CS_SUB, 0, 128,
368    0xfd, GB_CS_SUB, 1, 0,
369    0xfe, GB_CS_SUB, 2, 0,
370    0xff, GB_CS_SUB, 4, 0,
371    0
372};
373
374struct gb_exitfun {
375    void (*exitfun)();
376    gb_exitfun *next;
377};
378
379void GB_atexit(void (*exitfun)()) {
380    // called when GB_shell is destroyed (use similar to atexit())
381    //
382    // Since the program does not neccessarily terminated, your code calling
383    // GB_atexit() may run multiple times. Make sure everything is completely reset by your 'exitfun'
384
385    gb_exitfun *fun = new gb_exitfun;
386    fun->exitfun    = exitfun;
387
388    fun->next          = gb_local->atgbexit;
389    gb_local->atgbexit = fun;
390}
391
392static void run_and_destroy_exit_functions(gb_exitfun *fun) {
393    if (fun) {
394        fun->exitfun();
395        run_and_destroy_exit_functions(fun->next);
396        delete fun;
397    }
398}
399
400static void GB_exit_gb() {
401    GB_shell::ensure_inside();
402
403    if (gb_local) {
404        gb_local->~gb_local_data(); // inplace-dtor
405        gbm_free_mem(gb_local, sizeof(*gb_local), 0);
406        gb_local = NULL;
407        gbm_flush_mem();
408    }
409}
410
411gb_local_data::~gb_local_data() {
412    gb_assert(openedDBs == closedDBs);
413
414    run_and_destroy_exit_functions(atgbexit);
415
416    free(bitcompress);
417    gb_free_compress_tree(bituncompress);
418    free(write_buffer);
419
420    free(check_out_buffer(&buf2));
421    free(check_out_buffer(&buf1));
422    free(open_gb_mains);
423}
424
425// -----------------
426//      GB_shell
427
428
429static GB_shell *inside_shell = NULL;
430
431GB_shell::GB_shell() {
432    if (inside_shell) GBK_terminate("only one GB_shell allowed");
433    inside_shell = this;
434}
435GB_shell::~GB_shell() {
436    gb_assert(inside_shell == this);
437    GB_exit_gb();
438    inside_shell = NULL;
439}
440void GB_shell::ensure_inside()  { if (!inside_shell) GBK_terminate("Not inside GB_shell"); }
441
442bool GB_shell::in_shell() {
443    if (!inside_shell) {
444        return false;
445    }
446    return true;
447}
448
449struct GB_test_shell_closed {
450    ~GB_test_shell_closed() {
451        if (inside_shell) {
452            inside_shell->~GB_shell(); // call dtor
453        }
454    }
455};
456static GB_test_shell_closed test;
457
458void GB_init_gb() {
459    GB_shell::ensure_inside();
460
461    if (!gb_local) {
462        GBK_install_SIGSEGV_handler(true);          // never uninstalled
463        gbm_init_mem();
464        gb_local = (gb_local_data *)gbm_get_mem(sizeof(gb_local_data), 0);
465        ::new(gb_local) gb_local_data(); // inplace-ctor
466
467#ifdef ARBDB_SIZEDEBUG
468        arbdb_stat = (long *)GB_calloc(sizeof(long), 1000);
469#endif
470    }
471
472}
473
474int GB_open_DBs() { return gb_local ? gb_local->open_dbs() : 0; }
475
476gb_local_data::gb_local_data()
477{
478    init_buffer(&buf1, 4000);
479    init_buffer(&buf2, 4000);
480
481    write_bufsize = GBCM_BUFFER;
482    write_buffer  = (char *)malloc((size_t)write_bufsize);
483    write_ptr     = write_buffer;
484    write_free    = write_bufsize;
485
486    bituncompress = gb_build_uncompress_tree(GB_BIT_compress_data, 1, 0);
487    bitcompress   = gb_build_compress_list(GB_BIT_compress_data, 1, &(bc_size));
488
489    openedDBs = 0;
490    closedDBs = 0;
491
492    open_gb_mains = NULL;
493    open_gb_alloc = 0;
494
495    atgbexit = NULL;
496}
497
498void gb_local_data::announce_db_open(GB_MAIN_TYPE *Main) {
499    gb_assert(Main);
500    int idx = open_dbs();
501    if (idx >= open_gb_alloc) {
502        int            new_alloc = open_gb_alloc+10;
503        GB_MAIN_TYPE **new_mains = (GB_MAIN_TYPE**)realloc(open_gb_mains, new_alloc*sizeof(*new_mains));
504        memset(new_mains+open_gb_alloc, 0, 10*sizeof(*new_mains));
505        open_gb_alloc            = new_alloc;
506        open_gb_mains            = new_mains;
507    }
508    open_gb_mains[idx] = Main;
509    openedDBs++;
510}
511
512void gb_local_data::announce_db_close(GB_MAIN_TYPE *Main) {
513    gb_assert(Main);
514    int open = open_dbs();
515    int idx;
516    for (idx = 0; idx<open; ++idx) if (open_gb_mains[idx] == Main) break;
517
518    gb_assert(idx<open); // passed gb_main is unknown
519    if (idx<open) {
520        if (idx<(open-1)) { // not last
521            open_gb_mains[idx] = open_gb_mains[open-1];
522        }
523        closedDBs++;
524    }
525    if (closedDBs == openedDBs) {
526        GB_exit_gb(); // free most memory allocated by ARBDB library
527        // Caution: calling GB_exit_gb() frees 'this'!
528    }
529}
530
531static GBDATA *gb_remembered_db() {
532    GB_MAIN_TYPE *Main = gb_local ? gb_local->get_any_open_db() : NULL;
533    return Main ? (GBDATA*)Main->data : NULL;
534}
535
536GB_ERROR gb_unfold(GBCONTAINER *gbd, long deep, int index_pos) {
537    /*! get data from server.
538     *
539     * @param deep if != 0, then get subitems too.
540     * @param index_pos
541     * - >= 0, get indexed item from server
542     * - <0, get all items
543     *
544     * @return error on failure
545     */
546
547    GB_ERROR        error;
548    GBDATA         *gb2;
549    gb_header_list *header = GB_DATA_LIST_HEADER(gbd->d);
550
551    if (!gbd->flags2.folded_container) return 0;
552    if (index_pos> gbd->d.nheader) gb_create_header_array(gbd, index_pos + 1);
553    if (index_pos >= 0  && GB_HEADER_LIST_GBD(header[index_pos])) return 0;
554
555    if (GBCONTAINER_MAIN(gbd)->local_mode) {
556        GB_internal_error("Cannot unfold local_mode database");
557        return 0;
558    }
559
560    do {
561        if (index_pos<0) break;
562        if (index_pos >= gbd->d.nheader) break;
563        if (header[index_pos].flags.changed >= GB_DELETED) {
564            GB_internal_error("Tried to unfold a deleted item");
565            return 0;
566        }
567        if (GB_HEADER_LIST_GBD(header[index_pos])) return 0;            // already unfolded
568    } while (0);
569
570    error = gbcm_unfold_client(gbd, deep, index_pos);
571    if (error) {
572        GB_print_error();
573        return error;
574    }
575
576    if (index_pos<0) {
577        gb_untouch_children(gbd);
578        gbd->flags2.folded_container = 0;
579    }
580    else {
581        if ((gb2 = GBCONTAINER_ELEM(gbd, index_pos))) {
582            if (GB_TYPE(gb2) == GB_DB) gb_untouch_children((GBCONTAINER *)gb2);
583            gb_untouch_me(gb2);
584        }
585    }
586    return 0;
587}
588
589// -----------------------
590//      close database
591
592typedef void (*gb_close_callback)(GBDATA *gb_main, void *client_data);
593
594struct gb_close_callback_list {
595    gb_close_callback_list *next;
596    gb_close_callback       cb;
597    void                   *client_data;
598};
599
600#if defined(ASSERTION_USED)
601static bool atclose_cb_exists(gb_close_callback_list *gccs, gb_close_callback cb) {
602    return gccs && (gccs->cb == cb || atclose_cb_exists(gccs->next, cb));
603}
604#endif // ASSERTION_USED
605
606void GB_atclose(GBDATA *gbd, void (*fun)(GBDATA *gb_main, void *client_data), void *client_data) {
607    /*! Add a callback, which gets called directly before GB_close destroys all data.
608     * This is the recommended way to remove all callbacks from DB elements.
609     */
610
611    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
612
613    gb_assert(!atclose_cb_exists(Main->close_callbacks, fun)); // each close callback should only exist once
614
615    gb_close_callback_list *gccs = (gb_close_callback_list *)malloc(sizeof(*gccs));
616
617    gccs->next        = Main->close_callbacks;
618    gccs->cb          = fun;
619    gccs->client_data = client_data;
620
621    Main->close_callbacks = gccs;
622}
623
624static void run_close_callbacks(GBDATA *gb_main, gb_close_callback_list *gccs) {
625    while (gccs) {
626        gccs->cb(gb_main, gccs->client_data);
627        gb_close_callback_list *next = gccs->next;
628        free(gccs);
629        gccs = next;
630    }
631}
632
633static gb_callback_list *g_b_old_callback_list = NULL; // points to callback during callback (NULL otherwise)
634static GB_MAIN_TYPE     *g_b_old_main          = NULL; // points to DB root during callback (NULL otherwise)
635
636static GB_ERROR gb_do_callback_list(GB_MAIN_TYPE *Main) {
637    gb_callback_list *cbl, *cbl_next;
638    g_b_old_main = Main;
639
640    // first all delete callbacks:
641    for (cbl = Main->cbld; cbl;  cbl = cbl_next) {
642        g_b_old_callback_list = cbl;
643        cbl->func(cbl->gbd, cbl->clientdata, GB_CB_DELETE);
644        cbl_next = cbl->next;
645        g_b_old_callback_list = NULL;
646        gb_del_ref_gb_transaction_save(cbl->old);
647        gbm_free_mem(cbl, sizeof(gb_callback_list), GBM_CB_INDEX);
648    }
649
650    Main->cbld_last = NULL;
651    Main->cbld      = NULL;
652
653    // then all update callbacks:
654    for (cbl = Main->cbl; cbl;  cbl = cbl_next) {
655        g_b_old_callback_list = cbl;
656        cbl->func(cbl->gbd, cbl->clientdata, cbl->type);
657        cbl_next = cbl->next;
658        g_b_old_callback_list = NULL;
659        gb_del_ref_gb_transaction_save(cbl->old);
660        gbm_free_mem(cbl, sizeof(gb_callback_list), GBM_CB_INDEX);
661    }
662
663    g_b_old_main   = NULL;
664    Main->cbl_last = NULL;
665    Main->cbl      = NULL;
666
667    return 0;
668}
669
670void GB_close(GBDATA *gbd) {
671    GB_ERROR      error = NULL;
672    GB_MAIN_TYPE *Main  = GB_MAIN(gbd);
673
674    gb_assert(Main->transaction <= 0); // transaction running -> you can't close DB yet!
675
676    gb_assert((GBDATA*)Main->data == gbd);
677    run_close_callbacks(gbd, Main->close_callbacks);
678    Main->close_callbacks = 0;
679   
680    if (!Main->local_mode) {
681        long result            = gbcmc_close(Main->c_link);
682        if (result != 0) error = GBS_global_string("gbcmc_close returns %li", result);
683    }
684
685    gbcm_logout(Main, NULL);                        // logout default user
686   
687    if (!error) {
688        gb_assert(Main->close_callbacks == 0);
689
690        gb_delete_dummy_father(&Main->dummy_father);
691        Main->data = NULL;
692
693        /* ARBDB applications using awars easily crash in gb_do_callback_list(),
694         * if AWARs are still bound to elements in the closed database.
695         *
696         * To unlink awars call AW_root::unlink_awars_from_DB().
697         * If that doesn't help, test Main->data (often aka as GLOBAL_gb_main)
698         */
699        gb_do_callback_list(Main);                  // do all callbacks
700        gb_destroy_main(Main);
701    }
702
703    if (error) {
704        GB_warningf("Error in GB_close: %s", error);
705    }
706}
707
708void gb_close_unclosed_DBs() {
709    GBDATA *gb_main;
710    while ((gb_main = gb_remembered_db())) {
711        GB_close(gb_main);
712    }
713}
714
715// ------------------
716//      read data
717
718long GB_read_int(GBDATA *gbd)
719{
720    GB_TEST_READ(gbd, GB_INT, "GB_read_int");
721    return gbd->info.i;
722}
723
724int GB_read_byte(GBDATA *gbd)
725{
726    GB_TEST_READ(gbd, GB_BYTE, "GB_read_byte");
727    return gbd->info.i;
728}
729
730GBDATA *GB_read_pointer(GBDATA *gbd) {
731    GB_TEST_READ(gbd, GB_POINTER, "GB_read_pointer");
732    return gbd->info.ptr;
733}
734
735double GB_read_float(GBDATA *gbd)
736{
737    XDR          xdrs;
738    static float f;
739   
740    GB_TEST_READ(gbd, GB_FLOAT, "GB_read_float");
741    xdrmem_create(&xdrs, &gbd->info.in.data[0], SIZOFINTERN, XDR_DECODE);
742    xdr_float(&xdrs, &f);
743    xdr_destroy(&xdrs);
744
745    gb_assert(f == f); // !nan
746
747    return (double)f;
748}
749
750long GB_read_count(GBDATA *gbd) {
751    return GB_GETSIZE(gbd);
752}
753
754long GB_read_memuse(GBDATA *gbd) {
755    return GB_GETMEMSIZE(gbd);
756}
757
758GB_CSTR GB_read_pntr(GBDATA *gbd) {
759    int   type = GB_TYPE(gbd);
760    char *data = GB_GETDATA(gbd);
761
762    if (data) {
763        if (gbd->flags.compressed_data) {   // uncompressed data return pntr to database entry
764            char *ca = gb_read_cache(gbd);
765
766            if (!ca) {
767                long        size = GB_UNCOMPRESSED_SIZE(gbd, type);
768                const char *da   = gb_uncompress_data(gbd, data, size);
769
770                if (da) {
771                    ca = gb_alloc_cache_index(gbd, size);
772                    memcpy(ca, da, size);
773                }
774            }
775            data = ca;
776        }
777    }
778    return data;
779}
780
781int gb_read_nr(GBDATA *gbd) {
782    return gbd->index;
783}
784
785GB_CSTR GB_read_char_pntr(GBDATA *gbd)
786{
787    GB_TEST_READ(gbd, GB_STRING, "GB_read_char_pntr");
788    return GB_read_pntr(gbd);
789}
790
791char *GB_read_string(GBDATA *gbd)
792{
793    const char *d;
794    GB_TEST_READ(gbd, GB_STRING, "GB_read_string");
795    d = GB_read_pntr(gbd);
796    if (!d) return NULL;
797    return GB_memdup(d, GB_GETSIZE(gbd)+1);
798}
799
800long GB_read_string_count(GBDATA *gbd)
801{
802    GB_TEST_READ(gbd, GB_STRING, "GB_read_string_count");
803    return GB_GETSIZE(gbd);
804}
805
806GB_CSTR GB_read_link_pntr(GBDATA *gbd)
807{
808    GB_TEST_READ(gbd, GB_LINK, "GB_read_link_pntr");
809    return GB_read_pntr(gbd);
810}
811
812static char *GB_read_link(GBDATA *gbd)
813{
814    const char *d;
815    GB_TEST_READ(gbd, GB_LINK, "GB_read_link_pntr");
816    d = GB_read_pntr(gbd);
817    if (!d) return NULL;
818    return GB_memdup(d, GB_GETSIZE(gbd)+1);
819}
820
821long GB_read_bits_count(GBDATA *gbd)
822{
823    GB_TEST_READ(gbd, GB_BITS, "GB_read_bits_count");
824    return GB_GETSIZE(gbd);
825}
826
827GB_CSTR GB_read_bits_pntr(GBDATA *gbd, char c_0, char c_1)
828{
829    char *data;
830    long size;
831    GB_TEST_READ(gbd, GB_BITS, "GB_read_bits_pntr");
832    data = GB_GETDATA(gbd);
833    size = GB_GETSIZE(gbd);
834    if (!size) return 0;
835    {
836        char *ca = gb_read_cache(gbd);
837        char *da;
838        if (ca) return ca;
839        ca = gb_alloc_cache_index(gbd, size+1);
840        da = gb_uncompress_bits(data, size, c_0, c_1);
841        if (ca) {
842            memcpy(ca, da, size+1);
843            return ca;
844        }
845        else {
846            return da;
847        }
848    }
849}
850
851char *GB_read_bits(GBDATA *gbd, char c_0, char c_1) {
852    GB_CSTR d = GB_read_bits_pntr(gbd, c_0, c_1);
853    return d ? GB_memdup(d, GB_GETSIZE(gbd)+1) : 0;
854}
855
856
857GB_CSTR GB_read_bytes_pntr(GBDATA *gbd)
858{
859    GB_TEST_READ(gbd, GB_BYTES, "GB_read_bytes_pntr");
860    return GB_read_pntr(gbd);
861}
862
863long GB_read_bytes_count(GBDATA *gbd)
864{
865    GB_TEST_READ(gbd, GB_BYTES, "GB_read_bytes_count");
866    return GB_GETSIZE(gbd);
867}
868
869char *GB_read_bytes(GBDATA *gbd) {
870    GB_CSTR d = GB_read_bytes_pntr(gbd);
871    return d ? GB_memdup(d, GB_GETSIZE(gbd)) : 0;
872}
873
874GB_CUINT4 *GB_read_ints_pntr(GBDATA *gbd)
875{
876    GB_UINT4 *res;
877    GB_TEST_READ(gbd, GB_INTS, "GB_read_ints_pntr");
878
879    if (gbd->flags.compressed_data) {
880        res = (GB_UINT4 *)GB_read_pntr(gbd);
881    }
882    else {
883        res = (GB_UINT4 *)GB_GETDATA(gbd);
884    }
885    if (!res) return NULL;
886
887    if (0x01020304U == htonl(0x01020304U)) {
888        return res;
889    }
890    else {
891        long      i;
892        int       size = GB_GETSIZE(gbd);
893        char     *buf2 = GB_give_other_buffer((char *)res, size<<2);
894        GB_UINT4 *s    = (GB_UINT4 *)res;
895        GB_UINT4 *d    = (GB_UINT4 *)buf2;
896
897        for (i=size; i; i--) {
898            *(d++) = htonl(*(s++));
899        }
900        return (GB_UINT4 *)buf2;
901    }
902}
903
904long GB_read_ints_count(GBDATA *gbd) { // used by ../PERL_SCRIPTS/SAI/SAI.pm@read_ints_count
905    GB_TEST_READ(gbd, GB_INTS, "GB_read_ints_count");
906    return GB_GETSIZE(gbd);
907}
908
909GB_UINT4 *GB_read_ints(GBDATA *gbd)
910{
911    GB_CUINT4 *i = GB_read_ints_pntr(gbd);
912    if (!i) return NULL;
913    return  (GB_UINT4 *)GB_memdup((char *)i, GB_GETSIZE(gbd)*sizeof(GB_UINT4));
914}
915
916GB_CFLOAT *GB_read_floats_pntr(GBDATA *gbd)
917{
918    char *buf2;
919    char *res;
920
921    GB_TEST_READ(gbd, GB_FLOATS, "GB_read_floats_pntr");
922    if (gbd->flags.compressed_data) {
923        res = (char *)GB_read_pntr(gbd);
924    }
925    else {
926        res = (char *)GB_GETDATA(gbd);
927    }
928    if (!res) return NULL;
929    {
930        XDR    xdrs;
931        float *d;
932        long   i;
933        long   size      = GB_GETSIZE(gbd);
934        long   full_size = size*sizeof(float);
935
936        xdrmem_create(&xdrs, res, (int)(full_size), XDR_DECODE);
937        buf2 = GB_give_other_buffer(res, full_size);
938        d = (float *)buf2;
939        for (i=size; i; i--) {
940            xdr_float(&xdrs, d);
941            d++;
942        }
943        xdr_destroy(&xdrs);
944    }
945    return (float *)buf2;
946}
947
948static long GB_read_floats_count(GBDATA *gbd)
949{
950    GB_TEST_READ(gbd, GB_FLOATS, "GB_read_floats_count");
951    return GB_GETSIZE(gbd);
952}
953
954static float *GB_read_floats(GBDATA *gbd) // @@@ unused - check usage of floats
955{
956    GB_CFLOAT *f;
957    f = GB_read_floats_pntr(gbd);
958    if (!f) return NULL;
959    return  (float *)GB_memdup((char *)f, GB_GETSIZE(gbd)*sizeof(float));
960}
961
962char *GB_read_as_string(GBDATA *gbd)
963{
964    switch (GB_TYPE(gbd)) {
965        case GB_STRING: return GB_read_string(gbd);
966        case GB_LINK:   return GB_read_link(gbd);
967        case GB_BYTE:   return GBS_global_string_copy("%i", GB_read_byte(gbd));
968        case GB_INT:    return GBS_global_string_copy("%li", GB_read_int(gbd));
969        case GB_FLOAT:  return GBS_global_string_copy("%g", GB_read_float(gbd));
970        case GB_BITS:   return GB_read_bits(gbd, '0', '1');
971            /* Be careful : When adding new types here, you have to make sure that
972             * GB_write_as_string is able to write them back and that this makes sense.
973             */
974        default:    return NULL;
975    }
976}
977
978// ------------------------------------------------------------
979//      array type access functions (intended for perl use)
980
981long GB_read_from_ints(GBDATA *gbd, long index) { // used by ../PERL_SCRIPTS/SAI/SAI.pm@read_from_ints
982    static GBDATA    *last_gbd = 0;
983    static long       count    = 0;
984    static GB_CUINT4 *i        = 0;
985
986    if (gbd != last_gbd) {
987        count    = GB_read_ints_count(gbd);
988        i        = GB_read_ints_pntr(gbd);
989        last_gbd = gbd;
990    }
991
992    if (index >= 0 && index < count) {
993        return i[index];
994    }
995    return -1;
996}
997
998double GB_read_from_floats(GBDATA *gbd, long index) {
999    static GBDATA    *last_gbd = 0;
1000    static long       count    = 0;
1001    static GB_CFLOAT *f        = 0;
1002
1003    if (gbd != last_gbd) {
1004        count    = GB_read_floats_count(gbd);
1005        f        = GB_read_floats_pntr(gbd);
1006        last_gbd = gbd;
1007    }
1008
1009    if (index >= 0 && index < count) {
1010        return f[index];
1011    }
1012    return -1;
1013}
1014
1015// -------------------
1016//      write data
1017
1018static void gb_do_callbacks(GBDATA *gbd) {
1019    gb_assert(GB_MAIN(gbd)->transaction<0); // only use in "no transaction mode"!
1020
1021    GBDATA *gbdn, *gbdc;
1022    for (gbdc = gbd; gbdc; gbdc=gbdn) {
1023        gb_callback *cb, *cbn;
1024        gbdn = GB_get_father(gbdc);
1025        for (cb = GB_GET_EXT_CALLBACKS(gbdc); cb; cb = cbn) {
1026            cbn = cb->next;
1027            if (cb->type & GB_CB_CHANGED) {
1028                ++cb->running;
1029                cb->func(gbdc, cb->clientdata, GB_CB_CHANGED);
1030                --cb->running;
1031            }
1032        }
1033    }
1034}
1035
1036#define GB_DO_CALLBACKS(gbd) do { if (GB_MAIN(gbd)->transaction<0) gb_do_callbacks(gbd); } while (0)
1037
1038GB_ERROR GB_write_byte(GBDATA *gbd, int i)
1039{
1040    GB_TEST_WRITE(gbd, GB_BYTE, "GB_write_byte");
1041    if (gbd->info.i != i) {
1042        gb_save_extern_data_in_ts(gbd);
1043        gbd->info.i = i & 0xff;
1044        gb_touch_entry(gbd, GB_NORMAL_CHANGE);
1045        GB_DO_CALLBACKS(gbd);
1046    }
1047    return 0;
1048}
1049
1050GB_ERROR GB_write_int(GBDATA *gbd, long i) {
1051#if defined(ARB_64)
1052#if defined(WARN_TODO)
1053#warning GB_write_int should be GB_ERROR GB_write_int(GBDATA *gbd,int32_t i)
1054#endif
1055#endif
1056
1057    GB_TEST_WRITE(gbd, GB_INT, "GB_write_int");
1058    if ((long)((int32_t)i) != i) {
1059        gb_assert(0);
1060        GB_warningf("Warning: 64bit incompatibility detected\nNo data written to '%s'\n", GB_get_db_path(gbd));
1061        return "GB_INT out of range (signed, 32bit)";
1062    }
1063    if (gbd->info.i != (int32_t)i) {
1064        gb_save_extern_data_in_ts(gbd);
1065        gbd->info.i = i;
1066        gb_touch_entry(gbd, GB_NORMAL_CHANGE);
1067        GB_DO_CALLBACKS(gbd);
1068    }
1069    return 0;
1070}
1071
1072GB_ERROR GB_write_pointer(GBDATA *gbd, GBDATA *pointer) {
1073    GB_TEST_WRITE(gbd, GB_POINTER, "GB_write_pointer");
1074    if (gbd->info.ptr != pointer) {
1075        gb_save_extern_data_in_ts(gbd);
1076        gbd->info.ptr = pointer;
1077        gb_touch_entry(gbd, GB_NORMAL_CHANGE);
1078        GB_DO_CALLBACKS(gbd);
1079    }
1080    return 0;
1081}
1082
1083GB_ERROR GB_write_float(GBDATA *gbd, double f)
1084{
1085    gb_assert(f == f); // !nan
1086
1087    XDR          xdrs;
1088    static float f2;
1089
1090    GB_TEST_WRITE(gbd, GB_FLOAT, "GB_write_float");
1091
1092#if defined(WARN_TODO)
1093#warning call GB_read_float here!
1094#endif
1095    GB_TEST_READ(gbd, GB_FLOAT, "GB_read_float");
1096
1097    xdrmem_create(&xdrs, &gbd->info.in.data[0], SIZOFINTERN, XDR_DECODE);
1098    xdr_float(&xdrs, &f2);
1099    xdr_destroy(&xdrs);
1100
1101    if (f2 != f) {
1102        f2 = f;
1103        gb_save_extern_data_in_ts(gbd);
1104        xdrmem_create(&xdrs, &gbd->info.in.data[0], SIZOFINTERN, XDR_ENCODE);
1105        xdr_float(&xdrs, &f2);
1106        xdr_destroy(&xdrs);
1107        gb_touch_entry(gbd, GB_NORMAL_CHANGE);
1108        GB_DO_CALLBACKS(gbd);
1109    }
1110    xdr_destroy(&xdrs);
1111    return 0;
1112}
1113
1114GB_ERROR gb_write_compressed_pntr(GBDATA *gbd, const char *s, long memsize, long stored_size) {
1115    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1116    gb_free_cache(Main, gbd);
1117    gb_save_extern_data_in_ts(gbd);
1118    gbd->flags.compressed_data = 1;
1119    GB_SETSMDMALLOC(gbd, stored_size, (size_t)memsize, (char *)s);
1120    gb_touch_entry(gbd, GB_NORMAL_CHANGE);
1121    return 0;
1122}
1123
1124int gb_get_compression_mask(GB_MAIN_TYPE *Main, GBQUARK key, int gb_type) {
1125    gb_Key *ks = &Main->keys[key];
1126    int     compression_mask;
1127
1128    if (ks->gb_key_disabled) {
1129        compression_mask = 0;
1130    }
1131    else {
1132        if (!ks->gb_key) gb_load_single_key_data((GBDATA*)Main->data, key);
1133        compression_mask = gb_convert_type_2_compression_flags[gb_type] & ks->compression_mask;
1134    }
1135
1136    return compression_mask;
1137}
1138
1139GB_ERROR GB_write_pntr(GBDATA *gbd, const char *s, long bytes_size, long stored_size)
1140{
1141    // 'bytes_size' is the size of what 's' points to.
1142    // 'stored_size' is the size-information written into the DB
1143    //
1144    // e.g. for strings : stored_size = bytes_size-1, cause stored_size is string len,
1145    //                    but bytes_size includes zero byte.
1146
1147
1148    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1149    GBQUARK       key  = GB_KEY_QUARK(gbd);
1150    const char   *d;
1151    int           compression_mask;
1152    long          memsize;
1153    GB_TYPES      type = GB_TYPE(gbd);
1154
1155    gb_assert(implicated(type == GB_STRING, stored_size == bytes_size-1)); // size constraint for strings not fulfilled!
1156
1157    gb_free_cache(Main, gbd);
1158    gb_save_extern_data_in_ts(gbd);
1159
1160    compression_mask = gb_get_compression_mask(Main, key, type);
1161
1162    if (compression_mask) {
1163        d = gb_compress_data(gbd, key, s, bytes_size, &memsize, compression_mask, false);
1164    }
1165    else {
1166        d = NULL;
1167    }
1168    if (d) {
1169        gbd->flags.compressed_data = 1;
1170    }
1171    else {
1172        d = s;
1173        gbd->flags.compressed_data = 0;
1174        memsize = bytes_size;
1175    }
1176
1177    GB_SETSMDMALLOC(gbd, stored_size, memsize, d);
1178    gb_touch_entry(gbd, GB_NORMAL_CHANGE);
1179    GB_DO_CALLBACKS(gbd);
1180
1181    return 0;
1182}
1183
1184GB_ERROR GB_write_string(GBDATA *gbd, const char *s)
1185{
1186    long size;
1187    GB_TEST_WRITE(gbd, GB_STRING, "GB_write_string");
1188    GB_TEST_NON_BUFFER(s, "GB_write_string");        // compress would destroy the other buffer
1189
1190    if (!s) s = "";
1191    size      = strlen(s);
1192
1193    // no zero len strings allowed
1194    if ((GB_GETMEMSIZE(gbd))  && (size == GB_GETSIZE(gbd)))
1195    {
1196        if (!strcmp(s, GB_read_pntr(gbd)))
1197            return 0;
1198    }
1199#if defined(DEBUG) && 0
1200    // check for error (in compression)
1201    {
1202        GB_ERROR error = GB_write_pntr(gbd, s, size+1, size);
1203        if (!error) {
1204            char *check = GB_read_string(gbd);
1205
1206            gb_assert(check);
1207            gb_assert(strcmp(check, s) == 0);
1208
1209            free(check);
1210        }
1211        return error;
1212    }
1213#else
1214    return GB_write_pntr(gbd, s, size+1, size);
1215#endif // DEBUG
1216}
1217
1218GB_ERROR GB_write_link(GBDATA *gbd, const char *s)
1219{
1220    long size;
1221    GB_TEST_WRITE(gbd, GB_STRING, "GB_write_link");
1222    GB_TEST_NON_BUFFER(s, "GB_write_link");          // compress would destroy the other buffer
1223
1224    if (!s) s = "";
1225    size      = strlen(s);
1226
1227    // no zero len strings allowed
1228    if ((GB_GETMEMSIZE(gbd))  && (size == GB_GETSIZE(gbd)))
1229    {
1230        if (!strcmp(s, GB_read_pntr(gbd)))
1231            return 0;
1232    }
1233    return GB_write_pntr(gbd, s, size+1, size);
1234}
1235
1236
1237GB_ERROR GB_write_bits(GBDATA *gbd, const char *bits, long size, const char *c_0)
1238{
1239    char *d;
1240    long memsize;
1241
1242    GB_TEST_WRITE(gbd, GB_BITS, "GB_write_bits");
1243    GB_TEST_NON_BUFFER(bits, "GB_write_bits");       // compress would destroy the other buffer
1244    gb_save_extern_data_in_ts(gbd);
1245
1246    d = gb_compress_bits(bits, size, (const unsigned char *)c_0, &memsize);
1247    gbd->flags.compressed_data = 1;
1248    GB_SETSMDMALLOC(gbd, size, memsize, d);
1249    gb_touch_entry(gbd, GB_NORMAL_CHANGE);
1250    GB_DO_CALLBACKS(gbd);
1251    return 0;
1252}
1253
1254GB_ERROR GB_write_bytes(GBDATA *gbd, const char *s, long size)
1255{
1256    GB_TEST_WRITE(gbd, GB_BYTES, "GB_write_bytes");
1257    return GB_write_pntr(gbd, s, size, size);
1258}
1259
1260GB_ERROR GB_write_ints(GBDATA *gbd, const GB_UINT4 *i, long size)
1261{
1262
1263    GB_TEST_WRITE(gbd, GB_INTS, "GB_write_ints");
1264    GB_TEST_NON_BUFFER((char *)i, "GB_write_ints");  // compress would destroy the other buffer
1265
1266    if (0x01020304 != htonl((GB_UINT4)0x01020304)) {
1267        long      j;
1268        char     *buf2 = GB_give_other_buffer((char *)i, size<<2);
1269        GB_UINT4 *s    = (GB_UINT4 *)i;
1270        GB_UINT4 *d    = (GB_UINT4 *)buf2;
1271
1272        for (j=size; j; j--) {
1273            *(d++) = htonl(*(s++));
1274        }
1275        i = (GB_UINT4 *)buf2;
1276    }
1277    return GB_write_pntr(gbd, (char *)i, size* 4 /* sizeof(long4) */, size);
1278}
1279
1280GB_ERROR GB_write_floats(GBDATA *gbd, const float *f, long size)
1281{
1282    long fullsize = size * sizeof(float);
1283    GB_TEST_WRITE(gbd, GB_FLOATS, "GB_write_floats");
1284    GB_TEST_NON_BUFFER((char *)f, "GB_write_floats"); // compress would destroy the other buffer
1285
1286    {
1287        XDR    xdrs;
1288        long   i;
1289        char  *buf2 = GB_give_other_buffer((char *)f, fullsize);
1290        float *s    = (float *)f;
1291
1292        xdrmem_create(&xdrs, buf2, (int)fullsize, XDR_ENCODE);
1293        for (i=size; i; i--) {
1294            xdr_float(&xdrs, s);
1295            s++;
1296        }
1297        xdr_destroy (&xdrs);
1298        f = (float *)buf2;
1299    }
1300    return GB_write_pntr(gbd, (char *)f, size*sizeof(float), size);
1301}
1302
1303GB_ERROR GB_write_as_string(GBDATA *gbd, const char *val)
1304{
1305    switch (GB_TYPE(gbd)) {
1306        case GB_STRING: return GB_write_string(gbd, val);
1307        case GB_LINK:   return GB_write_link(gbd, val);
1308        case GB_BYTE:   return GB_write_byte(gbd, atoi(val));
1309        case GB_INT:    return GB_write_int(gbd, atoi(val));
1310        case GB_FLOAT:  return GB_write_float(gbd, GB_atof(val));
1311        case GB_BITS:   return GB_write_bits(gbd, val, strlen(val), "0");
1312        default:    return GB_export_errorf("Error: You cannot use GB_write_as_string on this type of entry (%s)", GB_read_key_pntr(gbd));
1313    }
1314}
1315
1316// ---------------------------
1317//      security functions
1318
1319int GB_read_security_write(GBDATA *gbd) {
1320    GB_test_transaction(gbd);
1321    return GB_GET_SECURITY_WRITE(gbd);
1322}
1323int GB_read_security_read(GBDATA *gbd) {
1324    GB_test_transaction(gbd);
1325    return GB_GET_SECURITY_READ(gbd);
1326}
1327int GB_read_security_delete(GBDATA *gbd) {
1328    GB_test_transaction(gbd);
1329    return GB_GET_SECURITY_DELETE(gbd);
1330}
1331GB_ERROR GB_write_security_write(GBDATA *gbd, unsigned long level)
1332{
1333    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1334    GB_test_transaction(Main);
1335
1336    if (GB_GET_SECURITY_WRITE(gbd)>Main->security_level)
1337        return gb_security_error(gbd);
1338    if (GB_GET_SECURITY_WRITE(gbd) == level) return 0;
1339    GB_PUT_SECURITY_WRITE(gbd, level);
1340    gb_touch_entry(gbd, GB_NORMAL_CHANGE);
1341    GB_DO_CALLBACKS(gbd);
1342    return 0;
1343}
1344GB_ERROR GB_write_security_read(GBDATA *gbd, unsigned long level) // @@@ unused
1345{
1346    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1347    GB_test_transaction(Main);
1348    if (GB_GET_SECURITY_WRITE(gbd)>Main->security_level)
1349        return gb_security_error(gbd);
1350    if (GB_GET_SECURITY_READ(gbd) == level) return 0;
1351    GB_PUT_SECURITY_READ(gbd, level);
1352    gb_touch_entry(gbd, GB_NORMAL_CHANGE);
1353    GB_DO_CALLBACKS(gbd);
1354    return 0;
1355}
1356GB_ERROR GB_write_security_delete(GBDATA *gbd, unsigned long level)
1357{
1358    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1359    GB_test_transaction(Main);
1360    if (GB_GET_SECURITY_WRITE(gbd)>Main->security_level)
1361        return gb_security_error(gbd);
1362    if (GB_GET_SECURITY_DELETE(gbd) == level) return 0;
1363    GB_PUT_SECURITY_DELETE(gbd, level);
1364    gb_touch_entry(gbd, GB_NORMAL_CHANGE);
1365    GB_DO_CALLBACKS(gbd);
1366    return 0;
1367}
1368GB_ERROR GB_write_security_levels(GBDATA *gbd, unsigned long readlevel, unsigned long writelevel, unsigned long deletelevel)
1369{
1370    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1371    GB_test_transaction(Main);
1372    if (GB_GET_SECURITY_WRITE(gbd)>Main->security_level)
1373        return gb_security_error(gbd);
1374    GB_PUT_SECURITY_WRITE(gbd, writelevel);
1375    GB_PUT_SECURITY_READ(gbd, readlevel);
1376    GB_PUT_SECURITY_DELETE(gbd, deletelevel);
1377    gb_touch_entry(gbd, GB_NORMAL_CHANGE);
1378    GB_DO_CALLBACKS(gbd);
1379    return 0;
1380}
1381
1382void GB_change_my_security(GBDATA *gbd, int level) {
1383    GB_MAIN(gbd)->security_level = level<0 ? 0 : (level>7 ? 7 : level);
1384}
1385
1386// For internal use only
1387void GB_push_my_security(GBDATA *gbd)
1388{
1389    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1390    Main->pushed_security_level++;
1391    if (Main->pushed_security_level <= 1) {
1392        Main->old_security_level = Main->security_level;
1393        Main->security_level = 7;
1394    }
1395}
1396
1397void GB_pop_my_security(GBDATA *gbd) {
1398    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1399    Main->pushed_security_level--;
1400    if (Main->pushed_security_level <= 0) {
1401        Main->security_level = Main->old_security_level;
1402    }
1403}
1404
1405
1406// ------------------------
1407//      Key information
1408
1409GB_TYPES GB_read_type(GBDATA *gbd) {
1410    GB_test_transaction(gbd);
1411    return (GB_TYPES)GB_TYPE(gbd);
1412}
1413
1414char *GB_read_key(GBDATA *gbd) {
1415    return strdup(GB_read_key_pntr(gbd));
1416}
1417
1418GB_CSTR GB_read_key_pntr(GBDATA *gbd) {
1419    GB_CSTR k;
1420    GB_test_transaction(gbd);
1421    k         = GB_KEY(gbd);
1422    if (!k) k = GBS_global_string("<invalid key (quark=%i)>", GB_KEY_QUARK(gbd));
1423    return k;
1424}
1425
1426GB_CSTR gb_read_key_pntr(GBDATA *gbd) {
1427    return GB_KEY(gbd);
1428}
1429
1430
1431GBQUARK gb_find_existing_quark(GB_MAIN_TYPE *Main, const char *key) {
1432    //! @return existing quark for 'key' (-1 if key == NULL, 0 if key is unknown)
1433    return key ? GBS_read_hash(Main->key_2_index_hash, key) : -1;
1434}
1435
1436GBQUARK gb_find_or_create_quark(GB_MAIN_TYPE *Main, const char *key) {
1437    //! @return existing or newly created quark for 'key'
1438    GBQUARK quark     = gb_find_existing_quark(Main, key);
1439    if (!quark) quark = gb_create_key(Main, key, true);
1440    return quark;
1441}
1442
1443GBQUARK gb_find_or_create_NULL_quark(GB_MAIN_TYPE *Main, const char *key) {
1444    // similar to gb_find_or_create_quark,
1445    // but if 'key' is NULL, quark 0 will be returned.
1446    //
1447    // Use this function with care.
1448    //
1449    // Known good use:
1450    // - create main entry and its dummy father via gb_make_container()
1451
1452    return key ? gb_find_or_create_quark(Main, key) : 0;
1453}
1454
1455GBQUARK GB_find_existing_quark(GBDATA *gbd, const char *key) {
1456    //! @return existing quark for 'key' (-1 if key == NULL, 0 if key is unknown)
1457    return gb_find_existing_quark(GB_MAIN(gbd), key);
1458}
1459
1460GBQUARK GB_find_or_create_quark(GBDATA *gbd, const char *key) {
1461    //! @return existing or newly created quark for 'key'
1462    return gb_find_or_create_quark(GB_MAIN(gbd), key);
1463}
1464
1465
1466// ---------------------------------------------
1467
1468GBQUARK GB_get_quark(GBDATA *gbd) {
1469    return GB_KEY_QUARK(gbd);
1470}
1471
1472bool GB_has_key(GBDATA *gbd, const char *key) {
1473    GBQUARK quark = GB_find_existing_quark(gbd, key); 
1474    return quark && (quark == GB_get_quark(gbd));
1475}
1476
1477// ---------------------------------------------
1478
1479long GB_read_clock(GBDATA *gbd) {
1480    if (GB_ARRAY_FLAGS(gbd).changed) return GB_MAIN(gbd)->clock;
1481    return GB_GET_EXT_UPDATE_DATE(gbd);
1482}
1483
1484long GB_read_transaction(GBDATA *gbd) {
1485    return GB_MAIN(gbd)->transaction;
1486}
1487
1488// ---------------------------------------------
1489//      Get and check the database hierarchy
1490
1491GBDATA *GB_get_father(GBDATA *gbd) {
1492    // Get the father of an entry
1493    GBDATA *father;
1494
1495    GB_test_transaction(gbd);
1496    if (!(father=(GBDATA*)GB_FATHER(gbd)))  return NULL;
1497    if (!GB_FATHER(father))         return NULL;
1498
1499    return father;
1500}
1501
1502GBDATA *GB_get_grandfather(GBDATA *gbd) {
1503    GBDATA *gb_grandpa;
1504    GB_test_transaction(gbd);
1505
1506    gb_grandpa = (GBDATA*)GB_FATHER(gbd);
1507    if (gb_grandpa) {
1508        gb_grandpa = (GBDATA*)GB_FATHER(gb_grandpa);
1509        if (gb_grandpa && !GB_FATHER(gb_grandpa)) {
1510            gb_grandpa = 0;
1511        }
1512    }
1513    return gb_grandpa;
1514}
1515
1516GBDATA *GB_get_root(GBDATA *gbd) {  // Get the root entry (gb_main)
1517    return (GBDATA *)GB_MAIN(gbd)->data;
1518}
1519
1520bool GB_check_father(GBDATA *gbd, GBDATA *gb_maybefather) {
1521    // Test whether an entry is a subentry of another
1522    GBDATA *gbfather;
1523    for (gbfather = GB_get_father(gbd);
1524         gbfather;
1525         gbfather = GB_get_father(gbfather))
1526    {
1527        if (gbfather == gb_maybefather) return true;
1528    }
1529    return false;
1530}
1531
1532// --------------------------
1533//      create and rename
1534
1535GBDATA *gb_create(GBDATA *father, const char *key, GB_TYPES type) {
1536    GBDATA *gbd = gb_make_entry((GBCONTAINER *)father, key, -1, 0, type);
1537    gb_touch_header(GB_FATHER(gbd));
1538    gb_touch_entry(gbd, GB_CREATED);
1539    return (GBDATA *)gbd;
1540}
1541
1542GBDATA *gb_create_container(GBDATA *father, const char *key) {
1543    // Create a container, do not check anything
1544    GBCONTAINER *gbd = gb_make_container((GBCONTAINER *)father, key, -1, 0);
1545    gb_touch_header(GB_FATHER(gbd));
1546    gb_touch_entry((GBDATA *)gbd, GB_CREATED);
1547    return (GBDATA *)gbd;
1548}
1549
1550GBDATA *GB_create(GBDATA *father, const char *key, GB_TYPES type) {
1551    /*! Create a DB entry
1552     *
1553     * @param father container to create DB field in
1554     * @param key name of field
1555     * @param type field type
1556     *
1557     * @return
1558     * - created DB entry
1559     * - NULL on failure (error is exported then)
1560     *
1561     * @see GB_create_container()
1562     */
1563    GBDATA *gbd;
1564
1565    if (GB_check_key(key)) {
1566        GB_print_error();
1567        return NULL;
1568    }
1569
1570    if (type == GB_DB) {
1571        gb_assert(type != GB_DB); // you like to use GB_create_container!
1572        GB_export_error("GB_create error: can't create containers");
1573        return NULL;
1574    }
1575
1576    if (!father) {
1577        GB_internal_errorf("GB_create error in GB_create:\nno father (key = '%s')", key);
1578        return NULL;
1579    }
1580    GB_test_transaction(father);
1581    if (GB_TYPE(father)!=GB_DB) {
1582        GB_export_errorf("GB_create: father (%s) is not of GB_DB type (%i) (creating '%s')",
1583                         GB_read_key_pntr(father), GB_TYPE(father), key);
1584        return NULL;
1585    };
1586
1587    if (type == GB_POINTER) {
1588        if (!GB_in_temporary_branch(father)) {
1589            GB_export_error("GB_create: pointers only allowed in temporary branches");
1590            return NULL;
1591        }
1592    }
1593
1594    // @@@ DRY vs gb_create
1595    gbd = gb_make_entry((GBCONTAINER *)father, key, -1, 0, type);
1596    gb_touch_header(GB_FATHER(gbd));
1597    gb_touch_entry(gbd, GB_CREATED);
1598
1599    gb_assert(GB_ARRAY_FLAGS(gbd).changed < GB_DELETED); // happens sometimes -> needs debugging
1600
1601    return gbd;
1602}
1603
1604GBDATA *GB_create_container(GBDATA *father, const char *key) {
1605    /*! Create a new DB container
1606     *
1607     * @param father parent container
1608     * @param key name of created container
1609     *
1610     * @return
1611     * - created container
1612     * - NULL on failure (error is exported then)
1613     *
1614     * @see GB_create()
1615     */
1616
1617    GBCONTAINER *gbd;
1618    if (GB_check_key(key)) {
1619        GB_print_error();
1620        return NULL;
1621    }
1622
1623    if ((*key == '\0')) {
1624        GB_export_error("GB_create error: empty key");
1625        return NULL;
1626    }
1627    if (!father) {
1628        GB_internal_errorf("GB_create error in GB_create:\nno father (key = '%s')", key);
1629        return NULL;
1630    }
1631    GB_test_transaction(father);
1632    if (GB_TYPE(father)!=GB_DB) {
1633        GB_export_errorf("GB_create: father (%s) is not of GB_DB type (%i) (creating '%s')",
1634                         GB_read_key_pntr(father), GB_TYPE(father), key);
1635        return NULL;
1636    };
1637    gbd = gb_make_container((GBCONTAINER *)father, key, -1, 0);
1638    gb_touch_header(GB_FATHER(gbd));
1639    gb_touch_entry((GBDATA *)gbd, GB_CREATED);
1640    return (GBDATA *)gbd;
1641}
1642
1643// ----------------------
1644//      recompression
1645
1646#if defined(WARN_TODO)
1647#warning rename gb_set_compression into gb_recompress (misleading name)
1648#endif
1649
1650static GB_ERROR gb_set_compression(GBDATA *source) {
1651    long type;
1652    GB_ERROR error = 0;
1653    GBDATA *gb_p;
1654    char *string;
1655
1656    GB_test_transaction(source);
1657    type = GB_TYPE(source);
1658
1659    switch (type) {
1660        case GB_STRING:
1661            string = GB_read_string(source);
1662            GB_write_string(source, "");
1663            GB_write_string(source, string);
1664            free(string);
1665            break;
1666        case GB_BITS:
1667        case GB_BYTES:
1668        case GB_INTS:
1669        case GB_FLOATS:
1670            break;
1671        case GB_DB:
1672            for (gb_p = GB_child(source); gb_p; gb_p = GB_nextChild(gb_p)) {
1673                error = gb_set_compression(gb_p);
1674                if (error) break;
1675            }
1676            break;
1677        default:
1678            break;
1679    }
1680    if (error) return error;
1681    return 0;
1682}
1683
1684bool GB_allow_compression(GBDATA *gb_main, bool allow_compression) {
1685    GB_MAIN_TYPE *Main      = GB_MAIN(gb_main);
1686    int           prev_mask = Main->compression_mask;
1687    Main->compression_mask  = allow_compression ? -1 : 0;
1688
1689    return prev_mask == 0 ? false : true;
1690}
1691
1692
1693#if defined(WARN_TODO)
1694#warning change param for GB_delete to GBDATA **
1695#endif
1696
1697GB_ERROR GB_delete(GBDATA *source) {
1698    GBDATA *gb_main;
1699
1700    GB_test_transaction(source);
1701    if (GB_GET_SECURITY_DELETE(source)>GB_MAIN(source)->security_level) {
1702        return GBS_global_string("Security error: deleting entry '%s' not permitted", GB_read_key_pntr(source));
1703    }
1704
1705    gb_main = GB_get_root(source);
1706
1707    if (source->flags.compressed_data) {
1708        bool was_allowed = GB_allow_compression(gb_main, false);
1709        gb_set_compression(source); // write data w/o compression (otherwise GB_read_old_value... won't work)
1710        GB_allow_compression(gb_main, was_allowed);
1711    }
1712
1713    {
1714        GB_MAIN_TYPE *Main = GB_MAIN(source);
1715        if (Main->transaction<0) {
1716            gb_delete_entry(&source);
1717            gb_do_callback_list(Main);
1718        }
1719        else {
1720            gb_touch_entry(source, GB_DELETED);
1721        }
1722    }
1723    return 0;
1724}
1725
1726GB_ERROR gb_delete_force(GBDATA *source)    // delete always
1727{
1728    gb_touch_entry(source, GB_DELETED);
1729    return 0;
1730}
1731
1732
1733// ------------------
1734//      Copy data
1735
1736#if defined(WARN_TODO)
1737#warning replace GB_copy with GB_copy_with_protection after release
1738#endif
1739
1740GB_ERROR GB_copy(GBDATA *dest, GBDATA *source) {
1741    return GB_copy_with_protection(dest, source, false);
1742}
1743
1744GB_ERROR GB_copy_with_protection(GBDATA *dest, GBDATA *source, bool copy_all_protections) {
1745    GB_TYPES type;
1746    GB_ERROR error = 0;
1747    GBDATA *gb_p;
1748    GBDATA *gb_d;
1749    GBCONTAINER *destc, *sourcec;
1750    const char *key;
1751
1752    GB_test_transaction(source);
1753    type = GB_TYPE(source);
1754    if (GB_TYPE(dest) != type)
1755    {
1756        return GB_export_errorf("incompatible types in GB_copy (source %s:%u != %s:%u",
1757                                GB_read_key_pntr(source), type, GB_read_key_pntr(dest), GB_TYPE(dest));
1758    }
1759
1760    switch (type)
1761    {
1762        case GB_INT:
1763            error = GB_write_int(dest, GB_read_int(source));
1764            break;
1765        case GB_FLOAT:
1766            error = GB_write_float(dest, GB_read_float(source));
1767            break;
1768        case GB_BYTE:
1769            error = GB_write_byte(dest, GB_read_byte(source));
1770            break;
1771        case GB_STRING:     // No local compression
1772            error = GB_write_string(dest, GB_read_char_pntr(source));
1773            break;
1774        case GB_LINK:       // No local compression
1775            error = GB_write_link(dest, GB_read_link_pntr(source));
1776            break;
1777        case GB_BITS:       // only local compressions for the following types
1778        case GB_BYTES:
1779        case GB_INTS:
1780        case GB_FLOATS:
1781            gb_save_extern_data_in_ts(dest);
1782            GB_SETSMDMALLOC(dest,   GB_GETSIZE(source),
1783                            GB_GETMEMSIZE(source),
1784                            GB_GETDATA(source));
1785            dest->flags.compressed_data = source->flags.compressed_data;
1786
1787            break;
1788        case GB_DB:
1789
1790            destc = (GBCONTAINER *)dest;
1791            sourcec = (GBCONTAINER *)source;
1792
1793            if (GB_TYPE(destc) != GB_DB)
1794            {
1795                GB_ERROR err = GB_export_errorf("GB_COPY Type conflict %s:%i != %s:%i",
1796                                                GB_read_key_pntr(dest), GB_TYPE(dest), GB_read_key_pntr(source), GB_DB);
1797                GB_internal_error(err);
1798                return err;
1799            }
1800
1801            if (source->flags2.folded_container)    gb_unfold((GBCONTAINER *)source, -1, -1);
1802            if (dest->flags2.folded_container)  gb_unfold((GBCONTAINER *)dest, 0, -1);
1803
1804            for (gb_p = GB_child(source); gb_p; gb_p = GB_nextChild(gb_p)) {
1805                GB_TYPES type2 = (GB_TYPES)GB_TYPE(gb_p);
1806
1807                key = GB_read_key_pntr(gb_p);
1808                if (type2 == GB_DB)
1809                {
1810                    gb_d = GB_create_container(dest, key);
1811                    gb_create_header_array((GBCONTAINER *)gb_d, ((GBCONTAINER *)gb_p)->d.size);
1812                }
1813                else
1814                {
1815                    gb_d = GB_create(dest, key, type2);
1816                }
1817
1818                if (!gb_d) error = GB_await_error();
1819                else error       = GB_copy_with_protection(gb_d, gb_p, copy_all_protections);
1820
1821                if (error) break;
1822            }
1823
1824            destc->flags3 = sourcec->flags3;
1825            break;
1826
1827        default:
1828            error = GB_export_error("GB_copy error unknown type");
1829    }
1830    if (error) return error;
1831
1832    gb_touch_entry(dest, GB_NORMAL_CHANGE);
1833
1834    dest->flags.security_read = source->flags.security_read;
1835    if (copy_all_protections) {
1836        dest->flags.security_write  = source->flags.security_write;
1837        dest->flags.security_delete = source->flags.security_delete;
1838    }
1839
1840    return 0;
1841}
1842
1843
1844static char *gb_stpcpy(char *dest, const char *source)
1845{
1846    while ((*dest++=*source++)) ;
1847    return dest-1; // return pointer to last copied character (which is \0)
1848}
1849
1850char* GB_get_subfields(GBDATA *gbd) {
1851    /*! Get all subfield names
1852     *
1853     * @return all subfields of 'gbd' as ';'-separated heap-copy
1854     * (first and last char of result is a ';')
1855     */
1856    long type;
1857    char *result = 0;
1858
1859    GB_test_transaction(gbd);
1860    type = GB_TYPE(gbd);
1861
1862    if (type==GB_DB) { // we are a container
1863        GBCONTAINER *gbc = (GBCONTAINER*)gbd;
1864        GBDATA *gbp;
1865        int result_length = 0;
1866
1867        if (gbc->flags2.folded_container) {
1868            gb_unfold(gbc, -1, -1);
1869        }
1870
1871        for (gbp = GB_child(gbd); gbp; gbp = GB_nextChild(gbp)) {
1872            const char *key = GB_read_key_pntr(gbp);
1873            int keylen = strlen(key);
1874
1875            if (result) {
1876                char *neu_result = (char*)malloc(result_length+keylen+1+1);
1877
1878                if (neu_result) {
1879                    char *p = gb_stpcpy(neu_result, result);
1880                    p = gb_stpcpy(p, key);
1881                    *p++ = ';';
1882                    p[0] = 0;
1883
1884                    freeset(result, neu_result);
1885                    result_length += keylen+1;
1886                }
1887                else {
1888                    gb_assert(0);
1889                }
1890            }
1891            else {
1892                result = (char*)malloc(1+keylen+1+1);
1893                result[0] = ';';
1894                strcpy(result+1, key);
1895                result[keylen+1] = ';';
1896                result[keylen+2] = 0;
1897                result_length = keylen+2;
1898            }
1899        }
1900    }
1901    else {
1902        result = strdup(";");
1903    }
1904
1905    return result;
1906}
1907
1908// --------------------------
1909//      temporary entries
1910
1911GB_ERROR GB_set_temporary(GBDATA *gbd) { // goes to header: __ATTR__USERESULT
1912    /*! if the temporary flag is set, then that entry (including all subentries) will not be saved
1913     * @see GB_clear_temporary() and GB_is_temporary()
1914     */
1915
1916    GB_ERROR error = NULL;
1917    GB_test_transaction(gbd);
1918
1919    if (GB_GET_SECURITY_DELETE(gbd)>GB_MAIN(gbd)->security_level) {
1920        error = GBS_global_string("Security error in GB_set_temporary: %s", GB_read_key_pntr(gbd));
1921    }
1922    else {
1923        gbd->flags.temporary = 1;
1924        gb_touch_entry(gbd, GB_NORMAL_CHANGE);
1925    }
1926    RETURN_ERROR(error);
1927}
1928
1929GB_ERROR GB_clear_temporary(GBDATA *gbd) { // @@@ used in ptpan branch - do not remove
1930    //! undo effect of GB_set_temporary()
1931
1932    GB_test_transaction(gbd);
1933    gbd->flags.temporary = 0;
1934    gb_touch_entry(gbd, GB_NORMAL_CHANGE);
1935    return 0;
1936}
1937
1938bool GB_is_temporary(GBDATA *gbd) {
1939    //! @see GB_set_temporary() and GB_in_temporary_branch()
1940    GB_test_transaction(gbd);
1941    return (long)gbd->flags.temporary;
1942}
1943
1944bool GB_in_temporary_branch(GBDATA *gbd) { // @@@ used in ptpan branch - do not remove
1945    /*! @return true, if 'gbd' is member of a temporary subtree,
1946     * i.e. if GB_is_temporary(itself or any parent)
1947     */
1948
1949    if (GB_is_temporary(gbd)) return true;
1950
1951    GBDATA *gb_parent = GB_get_father(gbd);
1952    if (!gb_parent) return false;
1953
1954    return GB_in_temporary_branch(gb_parent);
1955}
1956
1957// ---------------------
1958//      transactions
1959
1960
1961GB_ERROR GB_push_transaction(GBDATA *gbd) {
1962    /*! start a transaction if no transaction is running.
1963     * (otherwise only trace nested transactions)
1964     *
1965     * recommended transaction usage:
1966     *
1967     * \code
1968     * GB_ERROR myFunc() {
1969     *     GB_ERROR error = GB_push_transaction(gbd);
1970     *     if (!error) {
1971     *         error = ...;
1972     *     }
1973     *     return GB_end_transaction(gbd, error);
1974     * }
1975     *
1976     * void myFunc() {
1977     *     GB_ERROR error = GB_push_transaction(gbd);
1978     *     if (!error) {
1979     *         error = ...;
1980     *     }
1981     *     GB_end_transaction_show_error(gbd, error, aw_message);
1982     * }
1983     * \endcode
1984     *
1985     * @see GB_pop_transaction(), GB_end_transaction(), GB_begin_transaction()
1986     */
1987
1988    GB_MAIN_TYPE *Main  = GB_MAIN(gbd);
1989    GB_ERROR      error = 0;
1990
1991    if (Main->transaction == 0) error = GB_begin_transaction(gbd);
1992    else if (Main->transaction>0) Main->transaction++;
1993    // Main->transaction<0 is "no transaction mode"
1994
1995    return error;
1996}
1997
1998GB_ERROR GB_pop_transaction(GBDATA *gbd) {
1999    //! commit a transaction started with GB_push_transaction()
2000
2001    GB_ERROR      error;
2002    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
2003    if (Main->transaction==0) {
2004        error = GB_export_error("Pop without push");
2005        GB_internal_error(error);
2006        return  error;
2007    }
2008    if (Main->transaction<0) return 0;  // no transaction mode
2009    if (Main->transaction==1) {
2010        return GB_commit_transaction(gbd);
2011    }
2012    else {
2013        Main->transaction--;
2014    }
2015    return 0;
2016}
2017
2018GB_ERROR GB_begin_transaction(GBDATA *gbd) {
2019    /*! like GB_push_transaction(),
2020     * but fails if there is already an transaction running.
2021     * @see GB_commit_transaction() and GB_abort_transaction()
2022     */
2023
2024    GB_ERROR      error;
2025    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
2026    gbd                = (GBDATA *)Main->data;
2027    if (Main->transaction>0) {
2028        error = GB_export_errorf("GB_begin_transaction called %i !!!",
2029                                 Main->transaction);
2030        GB_internal_error(error);
2031        return GB_push_transaction(gbd);
2032    }
2033    if (Main->transaction<0) return 0;
2034    Main->transaction = 1;
2035    Main->aborted_transaction = 0;
2036    if (!Main->local_mode) {
2037        error = gbcmc_begin_transaction(gbd);
2038        if (error) return error;
2039        error = gb_commit_transaction_local_rek(gbd, 0, 0); // init structures
2040        gb_untouch_children((GBCONTAINER *)gbd);
2041        gb_untouch_me(gbd);
2042        if (error) return error;
2043    }
2044
2045    /* do all callbacks
2046     * cb that change the db are no problem, because it's the beginning of a ta
2047     */
2048    gb_do_callback_list(Main);
2049
2050    Main->clock ++;
2051    return 0;
2052}
2053
2054GB_ERROR gb_init_transaction(GBCONTAINER *gbd)      // the first transaction ever
2055{
2056    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
2057    GB_ERROR      error;
2058
2059    Main->transaction = 1;
2060
2061    error = gbcmc_init_transaction(Main->data);
2062    if (!error) Main->clock ++;
2063
2064    return error;
2065}
2066
2067GB_ERROR GB_no_transaction(GBDATA *gbd)
2068{
2069    GB_ERROR error;
2070    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
2071    if (!Main->local_mode) {
2072        error = GB_export_error("Tried to disable transactions in a client");
2073        GB_internal_error(error);
2074        return 0;
2075    }
2076    Main->transaction = -1;
2077    return 0;
2078}
2079
2080GB_ERROR GB_abort_transaction(GBDATA *gbd)
2081{
2082    /*! abort a running transaction,
2083     * i.e. forget all changes made to DB inside the current transaction.
2084     *
2085     * May be called instead of GB_pop_transaction() or GB_commit_transaction()
2086     *
2087     * If a nested transactions got aborted,
2088     * committing a surrounding transaction will silently abort it as well.
2089     */
2090
2091    GB_ERROR error;
2092    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
2093    gbd = (GBDATA *)Main->data;
2094    if (Main->transaction<=0) {
2095        GB_internal_error("No running Transaction");
2096        return GB_export_error("GB_abort_transaction: No running Transaction");
2097    }
2098    if (Main->transaction>1) {
2099        Main->aborted_transaction = 1;
2100        return GB_pop_transaction(gbd);
2101    }
2102
2103    gb_abort_transaction_local_rek(gbd, 0);
2104    if (!Main->local_mode) {
2105        error = gbcmc_abort_transaction(gbd);
2106        if (error) return error;
2107    }
2108    Main->clock--;
2109    gb_do_callback_list(Main);       // do all callbacks
2110    Main->transaction = 0;
2111    gb_untouch_children((GBCONTAINER *)gbd);
2112    gb_untouch_me(gbd);
2113    return 0;
2114}
2115
2116GB_ERROR GB_commit_transaction(GBDATA *gbd) {
2117    /*! commit a transaction started with GB_begin_transaction()
2118     *
2119     * commit changes made to DB.
2120     *
2121     * in case of nested transactions, this is equal to GB_pop_transaction()
2122     */
2123
2124    GB_ERROR      error = 0;
2125    GB_MAIN_TYPE *Main  = GB_MAIN(gbd);
2126    GB_CHANGE     flag;
2127
2128    gbd = (GBDATA *)Main->data;
2129    if (!Main->transaction) {
2130        error = GB_export_error("GB_commit_transaction: No running Transaction");
2131        GB_internal_error(error);
2132        return error;
2133    }
2134    if (Main->transaction>1) {
2135        GB_internal_error("Running GB_commit_transaction not at root transaction level");
2136        return GB_pop_transaction(gbd);
2137    }
2138    if (Main->aborted_transaction) {
2139        Main->aborted_transaction = 0;
2140        return      GB_abort_transaction(gbd);
2141    }
2142    if (Main->local_mode) {
2143        char *error1 = gb_set_undo_sync(gbd);
2144        while (1) {
2145            flag = (GB_CHANGE)GB_ARRAY_FLAGS(gbd).changed;
2146            if (!flag) break;           // nothing to do
2147            error = gb_commit_transaction_local_rek(gbd, 0, 0);
2148            gb_untouch_children((GBCONTAINER *)gbd);
2149            gb_untouch_me(gbd);
2150            if (error) break;
2151            gb_do_callback_list(Main);       // do all callbacks
2152        }
2153        gb_disable_undo(gbd);
2154        if (error1) {
2155            Main->transaction = 0;
2156            return error;
2157        }
2158    }
2159    else {
2160        gb_disable_undo(gbd);
2161        while (1) {
2162            flag = (GB_CHANGE)GB_ARRAY_FLAGS(gbd).changed;
2163            if (!flag) break;           // nothing to do
2164
2165            error = gbcmc_begin_sendupdate(gbd);        if (error) break;
2166            error = gb_commit_transaction_local_rek(gbd, 1, 0); if (error) break;
2167            error = gbcmc_end_sendupdate(gbd);      if (error) break;
2168
2169            gb_untouch_children((GBCONTAINER *)gbd);
2170            gb_untouch_me(gbd);
2171            gb_do_callback_list(Main);       // do all callbacks
2172        }
2173        if (!error) error = gbcmc_commit_transaction(gbd);
2174
2175    }
2176    Main->transaction = 0;
2177    if (error) return error;
2178    return 0;
2179}
2180
2181GB_ERROR GB_end_transaction(GBDATA *gbd, GB_ERROR error) {
2182    /*! abort or commit transaction
2183     *
2184     * @ param error
2185     * - if NULL commit transaction
2186     * - else abort transaction
2187     *
2188     * @return error or transaction error
2189     * @see GB_push_transaction() for example
2190     */
2191    if (error) GB_abort_transaction(gbd);
2192    else error = GB_pop_transaction(gbd);
2193    return error;
2194}
2195
2196void GB_end_transaction_show_error(GBDATA *gbd, GB_ERROR error, void (*error_handler)(GB_ERROR)) {
2197    //! like GB_end_transaction(), but show error using 'error_handler'
2198    error = GB_end_transaction(gbd, error);
2199    if (error) error_handler(error);
2200}
2201
2202int GB_get_transaction_level(GBDATA *gbd) {
2203    /*! @return transaction level
2204     * - 0 -> not in transaction
2205     * - 1 -> one single transaction
2206     * - 2, ... -> nested transactions
2207     */
2208    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
2209    return Main->transaction;
2210}
2211
2212#if defined(WARN_TODO)
2213#warning GB_update_server should be ARBDB-local!
2214#endif
2215
2216GB_ERROR GB_update_server(GBDATA *gbd) {
2217    //! Send updated data to server
2218    GB_ERROR      error = NULL;
2219    GB_MAIN_TYPE *Main  = GB_MAIN(gbd);
2220
2221    if (!Main->transaction) {
2222        error = "GB_update_server: No running Transaction";
2223        GB_internal_error(error);
2224    }
2225    else if (Main->local_mode) {
2226        error = "You cannot update the server as you are the server yourself";
2227    }
2228    else {
2229        GBDATA           *gb_main = (GBDATA *)Main->data;
2230        gb_callback_list *cbl_old = Main->cbl_last;
2231
2232        error = gbcmc_begin_sendupdate(gb_main);
2233        if (!error) {
2234            error = gb_commit_transaction_local_rek(gbd, 2, 0);
2235            if (!error) {
2236                error = gbcmc_end_sendupdate(gb_main);
2237                if (!error) {
2238                    if (cbl_old != Main->cbl_last) {
2239                        GB_internal_error("GB_update_server produced a callback, this is not allowed");
2240                    }
2241                    // gb_do_callback_list(gbd);         do all callbacks
2242                }
2243            }
2244        }
2245    }
2246    return error;
2247}
2248
2249// ------------------
2250//      callbacks
2251
2252void gb_add_changed_callback_list(GBDATA *gbd, gb_transaction_save *old, GB_CB_TYPE gbtype, GB_CB func, int *clientdata) {
2253    GB_MAIN_TYPE     *Main = GB_MAIN(gbd);
2254    gb_callback_list *cbl  = (gb_callback_list *)gbm_get_mem(sizeof(gb_callback_list), GBM_CB_INDEX);
2255
2256    if (Main->cbl) {
2257        Main->cbl_last->next = cbl;
2258    }
2259    else {
2260        Main->cbl = cbl;
2261    }
2262
2263    Main->cbl_last  = cbl;
2264    cbl->clientdata = clientdata;
2265    cbl->func       = func;
2266    cbl->gbd        = gbd;
2267    cbl->type       = gbtype;
2268   
2269    gb_add_ref_gb_transaction_save(old);
2270    cbl->old = old;
2271}
2272
2273void gb_add_delete_callback_list(GBDATA *gbd, gb_transaction_save *old, GB_CB func, int *clientdata) {
2274    GB_MAIN_TYPE     *Main = GB_MAIN(gbd);
2275    gb_callback_list *cbl  = (gb_callback_list *)gbm_get_mem(sizeof(gb_callback_list), GBM_CB_INDEX);
2276
2277    if (Main->cbld) {
2278        Main->cbld_last->next = cbl;
2279    }
2280    else {
2281        Main->cbld = cbl;
2282    }
2283    Main->cbld_last = cbl;
2284    cbl->clientdata = clientdata;
2285    cbl->func       = func;
2286    cbl->gbd        = gbd;
2287    cbl->type       = GB_CB_DELETE;
2288
2289    if (old) gb_add_ref_gb_transaction_save(old);
2290    cbl->old = old;
2291}
2292
2293GB_MAIN_TYPE *gb_get_main_during_cb() {
2294    /* if inside a callback, return the DB root of the DB element, the callback was called for.
2295     * if not inside a callback, return NULL.
2296     */
2297    return g_b_old_main;
2298}
2299
2300NOT4PERL bool GB_inside_callback(GBDATA *of_gbd, GB_CB_TYPE cbtype) {
2301    GB_MAIN_TYPE *Main   = gb_get_main_during_cb();
2302    bool          inside = false;
2303
2304    if (Main) {                 // inside a callback
2305        gb_assert(g_b_old_callback_list);
2306        if (g_b_old_callback_list->gbd == of_gbd) {
2307            GB_CB_TYPE curr_cbtype;
2308            if (Main->cbld) {       // delete callbacks were not all performed yet
2309                                    // -> current callback is a delete callback
2310                curr_cbtype = GB_CB_TYPE(g_b_old_callback_list->type & GB_CB_DELETE);
2311            }
2312            else {
2313                gb_assert(Main->cbl); // change callback
2314                curr_cbtype = GB_CB_TYPE(g_b_old_callback_list->type & (GB_CB_ALL-GB_CB_DELETE));
2315            }
2316            gb_assert(curr_cbtype != GB_CB_NONE); // wtf!? are we inside callback or not?
2317
2318            if ((cbtype&curr_cbtype) != GB_CB_NONE) {
2319                inside = true;
2320            }
2321        }
2322    }
2323
2324    return inside;
2325}
2326
2327GBDATA *GB_get_gb_main_during_cb() {
2328    GBDATA       *gb_main = NULL;
2329    GB_MAIN_TYPE *Main    = gb_get_main_during_cb();
2330
2331    if (Main) {                 // inside callback
2332        if (!GB_inside_callback((GBDATA*)Main->data, GB_CB_DELETE)) { // main is not deleted
2333            gb_main = (GBDATA*)Main->data;
2334        }
2335    }
2336    return gb_main;
2337}
2338
2339
2340
2341static GB_CSTR gb_read_pntr_ts(GBDATA *gbd, gb_transaction_save *ts) {
2342    int         type = GB_TYPE_TS(ts);
2343    const char *data = GB_GETDATA_TS(ts);
2344    if (data) {
2345        if (ts->flags.compressed_data) {    // uncompressed data return pntr to database entry
2346            long size = GB_GETSIZE_TS(ts) * gb_convert_type_2_sizeof[type] + gb_convert_type_2_appendix_size[type];
2347            data = gb_uncompress_data(gbd, data, size);
2348        }
2349    }
2350    return data;
2351}
2352
2353// get last array value in callbacks
2354NOT4PERL const void *GB_read_old_value() {
2355    char *data;
2356
2357    if (!g_b_old_callback_list) {
2358        GB_export_error("You cannot call GB_read_old_value outside a ARBDB callback");
2359        return NULL;
2360    }
2361    if (!g_b_old_callback_list->old) {
2362        GB_export_error("No old value available in GB_read_old_value");
2363        return NULL;
2364    }
2365    data = GB_GETDATA_TS(g_b_old_callback_list->old);
2366    if (!data) return NULL;
2367
2368    return gb_read_pntr_ts(g_b_old_callback_list->gbd, g_b_old_callback_list->old);
2369}
2370// same for size
2371long GB_read_old_size() {
2372    if (!g_b_old_callback_list) {
2373        GB_export_error("You cannot call GB_read_old_size outside a ARBDB callback");
2374        return -1;
2375    }
2376    if (!g_b_old_callback_list->old) {
2377        GB_export_error("No old value available in GB_read_old_size");
2378        return -1;
2379    }
2380    return GB_GETSIZE_TS(g_b_old_callback_list->old);
2381}
2382
2383char *GB_get_callback_info(GBDATA *gbd) {
2384    // returns human-readable information about callbacks of 'gbd' or 0
2385    char *result = 0;
2386    if (gbd->ext) {
2387        gb_callback *cb = gbd->ext->callback;
2388        while (cb) {
2389            char *cb_info = GBS_global_string_copy("func=%p type=%i clientdata=%p priority=%i",
2390                                                   (void*)cb->func, cb->type, cb->clientdata, cb->priority);
2391            if (result) {
2392                char *new_result = GBS_global_string_copy("%s\n%s", result, cb_info);
2393                free(result);
2394                free(cb_info);
2395                result = new_result;
2396            }
2397            else {
2398                result = cb_info;
2399            }
2400            cb = cb->next;
2401        }
2402    }
2403
2404    return result;
2405}
2406
2407static GB_ERROR GB_add_priority_callback(GBDATA *gbd, GB_CB_TYPE type, GB_CB func, int *clientdata, int priority) {
2408    /* Adds a callback to a DB entry.
2409     *
2410     * Callbacks with smaller priority values get executed before bigger priority values.
2411     *
2412     * Be careful when writing GB_CB_DELETE callbacks, there is a severe restriction:
2413     *
2414     * - the DB element may already be freed. The pointer is still pointing to the original
2415     *   location, so you can use it to identify the DB element, but you cannot dereference
2416     *   it under all circumstances.
2417     *
2418     * ARBDB internal delete-callbacks may use gb_get_main_during_cb() to access the DB root.
2419     * See also: GB_get_gb_main_during_cb()
2420     */
2421
2422#if defined(DEBUG)
2423    if (GB_inside_callback(gbd, GB_CB_DELETE)) {
2424        printf("Warning: GB_add_priority_callback called inside delete-callback of gbd (gbd may already be freed)\n");
2425#if defined(DEVEL_RALF)
2426        gb_assert(0); // fix callback-handling (never modify callbacks from inside delete callbacks)
2427#endif // DEVEL_RALF
2428    }
2429#endif // DEBUG
2430
2431    GB_test_transaction(gbd); // may return error
2432    GB_CREATE_EXT(gbd);
2433    gb_callback *cb = (gb_callback *)gbm_get_mem(sizeof(gb_callback), GB_GBM_INDEX(gbd));
2434
2435    if (gbd->ext->callback) {
2436        gb_callback *prev = 0;
2437        gb_callback *curr = gbd->ext->callback;
2438
2439        while (curr) {
2440            if (priority <= curr->priority) {
2441                // wanted priority is lower -> insert here
2442                break;
2443            }
2444
2445#if defined(DEVEL_RALF)
2446            // test if callback already was added (every callback shall only exist once). see below.
2447            gb_assert((curr->func != func) || (curr->clientdata != clientdata) || (curr->type != type));
2448#endif // DEVEL_RALF
2449
2450            prev = curr;
2451            curr = curr->next;
2452        }
2453
2454        if (prev) { prev->next = cb; }
2455        else { gbd->ext->callback = cb; }
2456
2457        cb->next = curr;
2458    }
2459    else {
2460        cb->next           = 0;
2461        gbd->ext->callback = cb;
2462    }
2463
2464    cb->type       = type;
2465    cb->clientdata = clientdata;
2466    cb->func       = func;
2467    cb->priority   = priority;
2468
2469#if defined(DEVEL_RALF)
2470#if defined(DEBUG)
2471    // test if callback already was added (every callback shall only exist once)
2472    // maybe you like to use GB_ensure_callback instead of GB_add_callback
2473    while (cb->next) {
2474        cb = cb->next;
2475        gb_assert((cb->func != func) || (cb->clientdata != clientdata) || (cb->type != type));
2476    }
2477#endif // DEBUG
2478#endif // DEVEL_RALF
2479
2480    return 0;
2481}
2482
2483GB_ERROR GB_add_callback(GBDATA *gbd, GB_CB_TYPE type, GB_CB func, int *clientdata) {
2484    return GB_add_priority_callback(gbd, type, func, clientdata, 5); // use default priority 5
2485}
2486
2487static void gb_remove_callback(GBDATA *gbd, GB_CB_TYPE type, GB_CB func, int *clientdata, bool cd_should_match) {
2488    bool exactly_one = cd_should_match; // remove exactly one callback
2489
2490#if defined(DEBUG)
2491    if (GB_inside_callback(gbd, GB_CB_DELETE)) {
2492        printf("Warning: gb_remove_callback called inside delete-callback of gbd (gbd may already be freed)\n");
2493#if defined(DEVEL_RALF)
2494        gb_assert(0); // fix callback-handling (never modify callbacks from inside delete callbacks)
2495#endif // DEVEL_RALF
2496    }
2497#endif // DEBUG
2498
2499    if (gbd->ext) {
2500        gb_callback **cb_ptr       = &gbd->ext->callback;
2501        gb_callback  *cb;
2502        short         prev_running = 0;
2503
2504        for (cb = *cb_ptr; cb; cb = *cb_ptr) {
2505            short this_running = cb->running;
2506
2507            if ((cb->func == func)  &&
2508                (cb->type == type) &&
2509                (cb->clientdata == clientdata || !cd_should_match))
2510            {
2511                if (prev_running || cb->running) {
2512                    // if the previous callback in list or the callback itself is running (in "no transaction mode")
2513                    // the callback cannot be removed (see gb_do_callbacks)
2514                    GBK_terminate("gb_remove_callback: tried to remove currently running callback");
2515                }
2516
2517                *cb_ptr = cb->next;
2518                gbm_free_mem(cb, sizeof(gb_callback), GB_GBM_INDEX(gbd));
2519                if (exactly_one) break;
2520            }
2521            else {
2522                cb_ptr = &cb->next;
2523            }
2524            prev_running = this_running;
2525        }
2526    }
2527}
2528
2529void GB_remove_callback(GBDATA *gbd, GB_CB_TYPE type, GB_CB func, int *clientdata) {
2530    // remove specific callback (type, func and clientdata must match)
2531    gb_remove_callback(gbd, type, func, clientdata, true);
2532}
2533
2534void GB_remove_all_callbacks_to(GBDATA *gbd, GB_CB_TYPE type, GB_CB func) {
2535    // removes all callbacks 'func' bound to 'gbd' with 'type'
2536    gb_remove_callback(gbd, type, func, 0, false);
2537}
2538
2539GB_ERROR GB_ensure_callback(GBDATA *gbd, GB_CB_TYPE type, GB_CB func, int *clientdata) {
2540    gb_callback *cb;
2541    for (cb = GB_GET_EXT_CALLBACKS(gbd); cb; cb = cb->next) {
2542        if ((cb->func == func) && (cb->clientdata == clientdata) && (cb->type == type)) {
2543            return NULL;        // already in cb list
2544        }
2545    }
2546    return GB_add_callback(gbd, type, func, clientdata);
2547}
2548
2549int GB_nsons(GBDATA *gbd) {
2550    /*! return number of child entries
2551     *
2552     * @@@ does this work in clients ?
2553     */
2554    if (GB_TYPE(gbd) != GB_DB) return 0;
2555    return ((GBCONTAINER *)gbd)->d.size;
2556}
2557
2558void GB_disable_quicksave(GBDATA *gbd, const char *reason) {
2559    /*! Disable quicksaving database
2560     * @param reason why quicksaving is not allowed
2561     */
2562    freedup(GB_MAIN(gbd)->qs.quick_save_disabled, reason);
2563}
2564
2565GB_ERROR GB_resort_data_base(GBDATA *gb_main, GBDATA **new_order_list, long listsize) {
2566    {
2567        long client_count = GB_read_clients(gb_main);
2568        if (client_count<0)
2569            return "Sorry: this program is not the arbdb server, you cannot resort your data";
2570
2571        if (client_count>0)
2572            return GBS_global_string("There are %li clients (editors, tree programs) connected to this server.\n"
2573                                     "You need to these close clients before you can run this operation.",
2574                                     client_count);
2575    }
2576
2577    if (listsize <= 0) return 0;
2578
2579    GBCONTAINER *father = GB_FATHER(new_order_list[0]);
2580    GB_disable_quicksave(gb_main, "some entries in the database got a new order");
2581
2582    gb_header_list *hl = GB_DATA_LIST_HEADER(father->d);
2583    for (long new_index = 0; new_index< listsize; new_index++) {
2584        long old_index = new_order_list[new_index]->index;
2585
2586        if (old_index < new_index) {
2587            GB_warningf("Warning at resort database: entry exists twice: %li and %li",
2588                        old_index, new_index);
2589        }
2590        else {
2591            GBDATA *ogb = GB_HEADER_LIST_GBD(hl[old_index]);
2592            GBDATA *ngb = GB_HEADER_LIST_GBD(hl[new_index]);
2593
2594            gb_header_list h = hl[new_index];
2595            hl[new_index] = hl[old_index];
2596            hl[old_index] = h;              // Warning: Relative Pointers are incorrect !!!
2597
2598            SET_GB_HEADER_LIST_GBD(hl[old_index], ngb);
2599            SET_GB_HEADER_LIST_GBD(hl[new_index], ogb);
2600
2601            if (ngb) ngb->index = old_index;
2602            if (ogb) ogb->index = new_index;
2603        }
2604    }
2605
2606    gb_touch_entry((GBDATA *)father, GB_NORMAL_CHANGE);
2607    return 0;
2608}
2609
2610GB_ERROR GB_resort_system_folder_to_top(GBDATA *gb_main) {
2611    GBDATA *gb_system = GB_entry(gb_main, GB_SYSTEM_FOLDER);
2612    GBDATA *gb_first = GB_child(gb_main);
2613    GBDATA **new_order_list;
2614    GB_ERROR error = 0;
2615    int i, len;
2616    if (GB_read_clients(gb_main)<0) return 0; // we are not server
2617    if (!gb_system) {
2618        return GB_export_error("System databaseentry does not exist");
2619    }
2620    if (gb_first == gb_system) return 0;
2621    len = GB_number_of_subentries(gb_main);
2622    new_order_list = (GBDATA **)GB_calloc(sizeof(GBDATA *), len);
2623    new_order_list[0] = gb_system;
2624    for (i=1; i<len; i++) {
2625        new_order_list[i] = gb_first;
2626        do {
2627            gb_first = GB_nextChild(gb_first);
2628        } while (gb_first == gb_system);
2629    }
2630    error = GB_resort_data_base(gb_main, new_order_list, len);
2631    free(new_order_list);
2632    return error;
2633}
2634
2635// ------------------------------
2636//      private(?) user flags
2637
2638long GB_read_usr_private(GBDATA *gbd) {
2639    GBCONTAINER *gbc = (GBCONTAINER *)gbd;
2640    if (GB_TYPE(gbc) != GB_DB) {
2641        GB_ERROR error = GB_export_errorf("GB_write_usr_private: not a container (%s)", GB_read_key_pntr(gbd));
2642        GB_internal_error(error);
2643        return 0;
2644    }
2645    return gbc->flags2.usr_ref;
2646}
2647
2648GB_ERROR GB_write_usr_private(GBDATA *gbd, long ref) {
2649    GBCONTAINER *gbc = (GBCONTAINER *)gbd;
2650    if (GB_TYPE(gbc) != GB_DB) {
2651        GB_ERROR error = GB_export_errorf("GB_write_usr_private: not a container (%s)", GB_read_key_pntr(gbd));
2652        GB_internal_error(error);
2653        return 0;
2654    }
2655    gbc->flags2.usr_ref = ref;
2656    return 0;
2657}
2658
2659// ------------------------
2660//      mark DB entries
2661
2662void GB_write_flag(GBDATA *gbd, long flag) {
2663    GBCONTAINER  *gbc  = (GBCONTAINER *)gbd;
2664    GB_MAIN_TYPE *Main = GB_MAIN(gbc);
2665
2666    GB_test_transaction(Main);
2667
2668    int ubit = Main->users[0]->userbit;
2669    int prev = GB_ARRAY_FLAGS(gbc).flags;
2670    gbd->flags.saved_flags = prev;
2671
2672    if (flag) {
2673        GB_ARRAY_FLAGS(gbc).flags |= ubit;
2674    }
2675    else {
2676        GB_ARRAY_FLAGS(gbc).flags &= ~ubit;
2677    }
2678    if (prev != (int)GB_ARRAY_FLAGS(gbc).flags) {
2679        gb_touch_entry(gbd, GB_NORMAL_CHANGE);
2680        gb_touch_header(GB_FATHER(gbd));
2681        GB_DO_CALLBACKS(gbd);
2682    }
2683}
2684
2685int GB_read_flag(GBDATA *gbd) {
2686    GB_test_transaction(gbd);
2687    if (GB_ARRAY_FLAGS(gbd).flags & GB_MAIN(gbd)->users[0]->userbit) return 1;
2688    else return 0;
2689}
2690
2691void GB_touch(GBDATA *gbd) {
2692    GB_test_transaction(gbd);
2693    gb_touch_entry(gbd, GB_NORMAL_CHANGE);
2694    GB_DO_CALLBACKS(gbd);
2695}
2696
2697
2698char GB_type_2_char(GB_TYPES type) {
2699    const char *type2char = "-bcif-B-CIFlSS-%";
2700    return type2char[type];
2701}
2702
2703GB_ERROR GB_print_debug_information(void */*dummy_AW_root*/, GBDATA *gb_main) {
2704    GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
2705    GB_push_transaction(gb_main);
2706    for (int i=0; i<Main->keycnt; i++) {
2707        if (Main->keys[i].key) {
2708            printf("%3i %20s    nref %i\n", i, Main->keys[i].key, (int)Main->keys[i].nref);
2709        }
2710        else {
2711            printf("    %3i unused key, next free key = %li\n", i, Main->keys[i].next_free_key);
2712        }
2713    }
2714    gbm_debug_mem();
2715    GB_pop_transaction(gb_main);
2716    return 0;
2717}
2718
2719static int GB_info_deep = 15;
2720
2721
2722static int gb_info(GBDATA *gbd, int deep) {
2723    GBCONTAINER *gbc;
2724    GB_TYPES type;
2725    char    *data;
2726    int     size;
2727    GB_MAIN_TYPE *Main;
2728
2729    if (gbd==NULL) { printf("NULL\n"); return -1; }
2730    GB_push_transaction(gbd);
2731    type = (GB_TYPES)GB_TYPE(gbd);
2732
2733    if (deep) {
2734        printf("    ");
2735    }
2736
2737    printf("(GBDATA*)0x%lx (GBCONTAINER*)0x%lx ", (long)gbd, (long)gbd);
2738
2739    if (gbd->rel_father==0) { printf("father=NULL\n"); return -1; }
2740
2741    if (type==GB_DB)    { gbc = (GBCONTAINER*) gbd; Main = GBCONTAINER_MAIN(gbc); }
2742    else        { gbc = NULL; Main = GB_MAIN(gbd); }
2743
2744    if (!Main)                  { printf("Oops - I have no main entry!!!\n"); return -1; }
2745    if (gbd==(GBDATA*)(Main->dummy_father))     { printf("dummy_father!\n"); return -1; }
2746
2747    printf("%10s Type '%c'  ", GB_read_key_pntr(gbd), GB_type_2_char(type));
2748
2749    switch (type)
2750    {
2751        case GB_DB:
2752            gbc = (GBCONTAINER *)gbd;
2753            size = gbc->d.size;
2754            printf("Size %i nheader %i hmemsize %i", gbc->d.size, gbc->d.nheader, gbc->d.headermemsize);
2755            printf(" father=(GBDATA*)0x%lx\n", (long)GB_FATHER(gbd));
2756            if (size < GB_info_deep) {
2757                int             index;
2758                gb_header_list *header;
2759
2760                header = GB_DATA_LIST_HEADER(gbc->d);
2761                for (index = 0; index < gbc->d.nheader; index++) {
2762                    GBDATA *gb_sub = GB_HEADER_LIST_GBD(header[index]);
2763                    printf("\t\t%10s (GBDATA*)0x%lx (GBCONTAINER*)0x%lx\n", Main->keys[header[index].flags.key_quark].key, (long)gb_sub, (long)gb_sub);
2764                }
2765            }
2766            break;
2767        default:
2768            data = GB_read_as_string(gbd);
2769            if (data) { printf("%s", data); free(data); }
2770            printf(" father=(GBDATA*)0x%lx\n", (long)GB_FATHER(gbd));
2771    }
2772
2773
2774    GB_pop_transaction(gbd);
2775
2776    return 0;
2777}
2778
2779
2780int GB_info(GBDATA *gbd)
2781{
2782    return gb_info(gbd, 0);
2783}
2784
2785long GB_number_of_subentries(GBDATA *gbd) {
2786    long subentries = -1;
2787
2788    if (GB_TYPE(gbd) == GB_DB) {
2789        GBCONTAINER    *gbc    = (GBCONTAINER*)gbd;
2790        gb_header_list *header = GB_DATA_LIST_HEADER(gbc->d);
2791
2792        subentries = 0;
2793        int end     = gbc->d.nheader;
2794        for (int index = 0; index<end; index++) {
2795            if (header[index].flags.changed < GB_DELETED) subentries++;
2796        }
2797    }
2798
2799    return subentries;
2800}
2801
2802// --------------------------------------------------------------------------------
2803
2804#ifdef UNIT_TESTS
2805
2806#include <test_unit.h>
2807
2808static void test_another_shell() { delete new GB_shell; }
2809static void test_opendb() { GB_close(GB_open("no.arb", "c")); }
2810
2811void TEST_GB_shell() {
2812    {
2813        GB_shell *shell = new GB_shell;
2814        TEST_ASSERT_SEGFAULT(test_another_shell);
2815        test_opendb(); // no SEGV here
2816        delete shell;
2817    }
2818
2819    TEST_ASSERT_SEGFAULT(test_opendb); // should be impossible to open db w/o shell
2820}
2821
2822void TEST_GB_number_of_subentries() {
2823    GB_shell  shell;
2824    GBDATA   *gb_main = GB_open("no.arb", "c");
2825
2826    {
2827        GB_transaction ta(gb_main);
2828
2829        GBDATA   *gb_cont = GB_create_container(gb_main, "container");
2830        TEST_ASSERT_EQUAL(GB_number_of_subentries(gb_cont), 0);
2831
2832        TEST_ASSERT_RESULT__NOERROREXPORTED(GB_create(gb_cont, "entry", GB_STRING));
2833        TEST_ASSERT_EQUAL(GB_number_of_subentries(gb_cont), 1);
2834
2835        {
2836            GBDATA *gb_entry;
2837            TEST_ASSERT_RESULT__NOERROREXPORTED(gb_entry = GB_create(gb_cont, "entry", GB_STRING));
2838            TEST_ASSERT_EQUAL(GB_number_of_subentries(gb_cont), 2);
2839
2840            TEST_ASSERT_NO_ERROR(GB_delete(gb_entry));
2841            TEST_ASSERT_EQUAL(GB_number_of_subentries(gb_cont), 1);
2842        }
2843
2844        TEST_ASSERT_RESULT__NOERROREXPORTED(GB_create(gb_cont, "entry", GB_STRING));
2845        TEST_ASSERT_EQUAL(GB_number_of_subentries(gb_cont), 2);
2846    }
2847
2848    GB_close(gb_main);
2849}
2850
2851#endif
Note: See TracBrowser for help on using the browser.