source: tags/arb_5.1/ARBDB/arbdb.c

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