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

Last change on this file was 6149, checked in by westram, 15 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 78.9 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
848    gb_free_cache(Main,gbd);
849    gb_save_extern_data_in_ts(gbd);
850
851    compression_mask = gb_get_compression_mask(Main, key, GB_TYPE(gbd));
852
853    if (compression_mask){
854        d = gb_compress_data(gbd, key, s, bytes_size, &memsize, compression_mask, GB_FALSE);
855    }
856    else {
857        d = NULL;
858    }
859    if (d) {
860        gbd->flags.compressed_data = 1;
861    }
862    else {
863        d = s;
864        gbd->flags.compressed_data = 0;
865        memsize = bytes_size;
866    }
867
868    GB_SETSMDMALLOC(gbd,stored_size,memsize,d);
869    gb_touch_entry(gbd,gb_changed);
870    GB_DO_CALLBACKS(gbd);
871
872    return 0;
873}
874
875GB_ERROR GB_write_string(GBDATA *gbd,const char *s)
876{
877    long size;
878    /*fprintf(stderr, "GB_write_string(%p, %s);\n", gbd, s);*/
879    GB_TEST_WRITE(gbd,GB_STRING,"GB_write_string");
880    GB_TEST_NON_BUFFER(s,"GB_write_string");        /* compress would destroy the other buffer */
881   
882    if (!s) s = "";
883    size      = strlen(s);
884
885    /* no zero len strings allowed */
886    if ((GB_GETMEMSIZE(gbd))  && (size == GB_GETSIZE(gbd)))
887    {
888        if (!strcmp(s,GB_read_pntr(gbd)))
889            return 0;
890    }
891#if defined(DEBUG) && 0
892    // check for error (in compression)
893    {
894        GB_ERROR error = GB_write_pntr(gbd,s,size+1,size);
895        if (!error) {
896            char *check = GB_read_string(gbd);
897
898            gb_assert(check);
899            gb_assert(strcmp(check, s) == 0);
900
901            free(check);
902        }
903        return error;
904    }
905#else
906    return GB_write_pntr(gbd,s,size+1,size);
907#endif /* DEBUG */
908}
909
910GB_ERROR GB_write_link(GBDATA *gbd,const char *s)
911{
912    long size;
913    GB_TEST_WRITE(gbd,GB_STRING,"GB_write_link");
914    GB_TEST_NON_BUFFER(s,"GB_write_link");          /* compress would destroy the other buffer */
915   
916    if (!s) s = "";
917    size      = strlen(s);
918
919    /* no zero len strings allowed */
920    if ((GB_GETMEMSIZE(gbd))  && (size == GB_GETSIZE(gbd)))
921    {
922        if (!strcmp(s,GB_read_pntr(gbd)))
923            return 0;
924    }
925    return GB_write_pntr(gbd,s,size+1,size);
926}
927
928
929GB_ERROR GB_write_bits(GBDATA *gbd,const char *bits,long size, const char *c_0)
930{
931    char *d;
932    long memsize[2];
933
934    GB_TEST_WRITE(gbd,GB_BITS,"GB_write_bits");
935    GB_TEST_NON_BUFFER(bits,"GB_write_bits");       /* compress would destroy the other buffer */
936    gb_save_extern_data_in_ts(gbd);
937
938    d = gb_compress_bits(bits,size,(const unsigned char *)c_0,memsize);
939    gbd->flags.compressed_data = 1;
940    GB_SETSMDMALLOC(gbd,size,memsize[0],d);
941    gb_touch_entry(gbd,gb_changed);
942    GB_DO_CALLBACKS(gbd);
943    return 0;
944}
945
946GB_ERROR GB_write_bytes(GBDATA *gbd,const char *s,long size)
947{
948    GB_TEST_WRITE(gbd,GB_BYTES,"GB_write_bytes");
949    return GB_write_pntr(gbd,s,size,size);
950}
951
952GB_ERROR GB_write_ints(GBDATA *gbd,const GB_UINT4 *i,long size)
953{
954
955    GB_TEST_WRITE(gbd,GB_INTS,"GB_write_ints");
956    GB_TEST_NON_BUFFER((char *)i,"GB_write_ints");  /* compress would destroy the other buffer */
957
958    if ( 0x01020304 != htonl((GB_UINT4)0x01020304) ) {
959        long      j;
960        char     *buf2 = GB_give_other_buffer((char *)i,size<<2);
961        GB_UINT4 *s    = (GB_UINT4 *)i;
962        GB_UINT4 *d    = (GB_UINT4 *)buf2;
963       
964        for (j=size;j;j--) {
965            *(d++) = htonl(*(s++));
966        }
967        i = (GB_UINT4 *)buf2;
968    }
969    return GB_write_pntr(gbd,(char *)i,size* 4 /*sizeof(long4)*/,size);
970}
971
972GB_ERROR GB_write_floats(GBDATA *gbd,const float *f,long size)
973{
974    long fullsize = size * sizeof(float);
975    GB_TEST_WRITE(gbd,GB_FLOATS,"GB_write_floats");
976    GB_TEST_NON_BUFFER((char *)f,"GB_write_floats"); /* compress would destroy the other buffer */
977
978    {
979        XDR    xdrs;
980        long   i;
981        char  *buf2 = GB_give_other_buffer((char *)f,fullsize);
982        float *s    = (float *)f;
983
984        xdrmem_create(&xdrs, buf2 ,(int)fullsize ,XDR_ENCODE);
985        for (i=size;i;i--) {
986            xdr_float(&xdrs,s);
987            s++;
988        }
989        xdr_destroy (&xdrs);
990        f = (float *)buf2;
991    }
992    return GB_write_pntr(gbd,(char *)f,size*sizeof(float),size);
993}
994
995GB_ERROR GB_write_as_string(GBDATA *gbd,const char *val)
996{
997    switch (GB_TYPE(gbd)) {
998        case GB_STRING: return GB_write_string(gbd,val);
999        case GB_LINK:   return GB_write_link(gbd,val);
1000        case GB_BYTE:   return GB_write_byte(gbd,atoi(val));
1001        case GB_INT:    return GB_write_int(gbd,atoi(val));
1002        case GB_FLOAT:  return GB_write_float(gbd,GB_atof(val));
1003        case GB_BITS:   return GB_write_bits(gbd,val,strlen(val),"0");
1004        default:    return GB_export_errorf("Error: You cannot use GB_write_as_string on this type of entry (%s)",GB_read_key_pntr(gbd));
1005    }
1006}
1007
1008
1009/********************************************************************************************
1010                    Key Information
1011********************************************************************************************/
1012int GB_read_security_write(GBDATA *gbd)
1013{
1014    GB_TEST_TRANSACTION(gbd);
1015    return GB_GET_SECURITY_WRITE(gbd);}
1016int GB_read_security_read(GBDATA *gbd)
1017{
1018    GB_TEST_TRANSACTION(gbd);
1019    return GB_GET_SECURITY_READ(gbd);}
1020int GB_read_security_delete(GBDATA *gbd)
1021{
1022    GB_TEST_TRANSACTION(gbd);
1023    return GB_GET_SECURITY_DELETE(gbd);}
1024
1025int GB_get_my_security(GBDATA *gbd)
1026{
1027    return GB_MAIN(gbd)->security_level;
1028}
1029
1030GB_ERROR gb_security_error(GBDATA *gbd){
1031    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1032    const char *error  = GB_export_errorf("Protection: Attempt to change a level-%i-'%s'-entry, \n"
1033                                          "but your current security level is only %i",
1034                                          GB_GET_SECURITY_WRITE(gbd),
1035                                          GB_read_key_pntr(gbd),
1036                                          Main->security_level);
1037
1038#if defined(DEBUG)
1039    fprintf(stderr, "%s\n", error);
1040#endif /* DEBUG */
1041    return error;
1042}
1043
1044GB_ERROR GB_write_security_write(GBDATA *gbd,unsigned long level)
1045{
1046    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1047    GB_TEST_TRANSACTION(gbd);
1048
1049    if (GB_GET_SECURITY_WRITE(gbd)>Main->security_level)
1050        return gb_security_error(gbd);
1051    if (GB_GET_SECURITY_WRITE(gbd) == level) return 0;
1052    GB_PUT_SECURITY_WRITE(gbd,level);
1053    gb_touch_entry(gbd,gb_changed);
1054    GB_DO_CALLBACKS(gbd);
1055    return 0;
1056}
1057GB_ERROR GB_write_security_read(GBDATA *gbd,unsigned long level)
1058{
1059    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1060    GB_TEST_TRANSACTION(gbd);
1061    if (GB_GET_SECURITY_WRITE(gbd)>Main->security_level)
1062        return gb_security_error(gbd);
1063    if (GB_GET_SECURITY_READ(gbd) == level) return 0;
1064    GB_PUT_SECURITY_READ(gbd,level);
1065    gb_touch_entry(gbd,gb_changed);
1066    GB_DO_CALLBACKS(gbd);
1067    return 0;
1068}
1069
1070GB_ERROR GB_write_security_delete(GBDATA *gbd,unsigned long level)
1071{
1072    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1073    GB_TEST_TRANSACTION(gbd);
1074    if (GB_GET_SECURITY_WRITE(gbd)>Main->security_level)
1075        return gb_security_error(gbd);
1076    if (GB_GET_SECURITY_DELETE(gbd) == level) return 0;
1077    GB_PUT_SECURITY_DELETE(gbd,level);
1078    gb_touch_entry(gbd,gb_changed);
1079    GB_DO_CALLBACKS(gbd);
1080    return 0;
1081}
1082GB_ERROR GB_write_security_levels(GBDATA *gbd,unsigned long readlevel,unsigned long writelevel,unsigned long deletelevel)
1083{
1084    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1085    GB_TEST_TRANSACTION(gbd);
1086    if (GB_GET_SECURITY_WRITE(gbd)>Main->security_level)
1087        return gb_security_error(gbd);
1088    GB_PUT_SECURITY_WRITE(gbd,writelevel);
1089    GB_PUT_SECURITY_READ(gbd,readlevel);
1090    GB_PUT_SECURITY_DELETE(gbd,deletelevel);
1091    gb_touch_entry(gbd,gb_changed);
1092    GB_DO_CALLBACKS(gbd);
1093    return 0;
1094}
1095
1096GB_ERROR GB_change_my_security(GBDATA *gbd,int level,const char *passwd)
1097{
1098    int i;
1099    i = level;
1100    if (i<0) i=0;
1101    if (i>=8) i = 7;
1102    GB_MAIN(gbd)->security_level = i;
1103    passwd = passwd;    /*dummy for compiler */
1104    return 0;
1105}
1106
1107/* For internal use only */
1108void GB_push_my_security(GBDATA *gbd)
1109{
1110    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1111    Main->pushed_security_level++;
1112    if (Main->pushed_security_level <= 1) {
1113        Main->old_security_level = Main->security_level;
1114        Main->security_level = 7;
1115    }
1116}
1117
1118void GB_pop_my_security(GBDATA *gbd) {
1119    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1120    Main->pushed_security_level--;
1121    if (Main->pushed_security_level <= 0) {
1122        Main->security_level = Main->old_security_level;
1123    }
1124}
1125
1126GB_TYPES GB_read_type(GBDATA *gbd) {
1127    GB_TEST_TRANSACTION(gbd);
1128    return (GB_TYPES)GB_TYPE(gbd);
1129}
1130
1131char *GB_read_key(GBDATA *gbd) {
1132    return strdup(GB_read_key_pntr(gbd));
1133}
1134
1135GB_CSTR GB_read_key_pntr(GBDATA *gbd) {
1136    GB_CSTR k;
1137    GB_TEST_TRANSACTION(gbd);
1138    k         = GB_KEY(gbd);
1139    if (!k) k = GBS_global_string("<invalid key (quark=%i)>", GB_KEY_QUARK(gbd));
1140    return k;
1141}
1142
1143GB_CSTR gb_read_key_pntr(GBDATA *gbd){
1144    return GB_KEY(gbd);
1145}
1146
1147
1148GBQUARK GB_key_2_quark(GBDATA *gbd, const char *s) {
1149    long          index;
1150    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1151
1152    if (!s) return -1;
1153    index = GBS_read_hash(Main->key_2_index_hash,s);
1154    if (!index) {   /* create new index */
1155        index = gb_create_key(Main,s,GB_TRUE);
1156    }
1157    return (GBQUARK)index;
1158}
1159
1160GBQUARK GB_get_quark(GBDATA *gbd) {
1161    return GB_KEY_QUARK(gbd);
1162}
1163
1164GB_BOOL GB_has_key(GBDATA *gbd, const char *key) {
1165    GBQUARK quark = GB_key_2_quark(gbd, key);
1166    return (quark == GB_get_quark(gbd));
1167}
1168
1169GBQUARK gb_key_2_quark(GB_MAIN_TYPE *Main, const char *s) {
1170    long index;
1171    if (!s) return 0;
1172    index = GBS_read_hash(Main->key_2_index_hash,s);
1173    if (!index) {   /* create new index */
1174        index = gb_create_key(Main,s,GB_TRUE);
1175    }
1176    return (GBQUARK)index;
1177}
1178
1179
1180
1181
1182long GB_read_clock(GBDATA *gbd)
1183{
1184    if (GB_ARRAY_FLAGS(gbd).changed) return GB_MAIN(gbd)->clock;
1185    return GB_GET_EXT_UPDATE_DATE(gbd);
1186}
1187
1188long    GB_read_transaction(GBDATA *gbd)
1189{
1190    return GB_MAIN(gbd)->transaction;
1191}
1192
1193/********************************************************************************************
1194                    Get and check the database hierarchy
1195********************************************************************************************/
1196
1197GBDATA *GB_get_father(GBDATA *gbd) {
1198    /* Get the father of an entry */
1199    GBDATA *father;
1200
1201    GB_TEST_TRANSACTION(gbd);
1202    if (!(father=(GBDATA*)GB_FATHER(gbd)))  return NULL;
1203    if (!GB_FATHER(father))         return NULL;
1204
1205    return father;
1206}
1207
1208GBDATA *GB_get_grandfather(GBDATA *gbd) {
1209    GBDATA *gb_grandpa;
1210    GB_TEST_TRANSACTION(gbd);
1211
1212    gb_grandpa = (GBDATA*)GB_FATHER(gbd);
1213    if (gb_grandpa) {
1214        gb_grandpa = (GBDATA*)GB_FATHER(gb_grandpa);
1215        if (gb_grandpa && !GB_FATHER(gb_grandpa)) {
1216            gb_grandpa = 0;
1217        }
1218    }
1219    return gb_grandpa;
1220}
1221
1222GBDATA *GB_get_root(GBDATA *gbd) {  /* Get the root entry (gb_main) */
1223    return (GBDATA *)GB_MAIN(gbd)->data;
1224}
1225
1226GB_BOOL GB_check_father(GBDATA *gbd, GBDATA *gb_maybefather) {
1227    /* Test whether an entry is a subentry of another */
1228    GBDATA *gbfather;
1229    for (gbfather = GB_get_father(gbd);
1230         gbfather;
1231         gbfather = GB_get_father(gbfather))
1232    {
1233        if (gbfather == gb_maybefather) return GB_TRUE;
1234    }
1235    return GB_FALSE;
1236}
1237
1238GBDATA *gb_create(GBDATA *father,const char *key, GB_TYPES type){
1239    GBDATA *gbd = gb_make_entry((GBCONTAINER *)father, key, -1,0,type);
1240    gb_touch_header(GB_FATHER(gbd));
1241    gb_touch_entry(gbd,gb_created);
1242    return (GBDATA *)gbd;
1243}
1244
1245/* Create a container, do not check anything */
1246GBDATA *gb_create_container(GBDATA *father, const char *key){
1247    GBCONTAINER *gbd = gb_make_container((GBCONTAINER *)father,key, -1, 0);
1248    gb_touch_header(GB_FATHER(gbd));
1249    gb_touch_entry((GBDATA *)gbd,gb_created);
1250    return (GBDATA *)gbd;
1251}
1252
1253void gb_rename(GBCONTAINER *gbc, const char *new_key) {
1254    gb_rename_entry(gbc, new_key);
1255}
1256
1257/* User accessible rename, check everything
1258 * returns 0 if successful!
1259 */
1260int GB_rename(GBDATA *gbc, const char *new_key) {
1261    GBCONTAINER *old_father, *new_father;
1262    if (GB_check_key(new_key)) {
1263        GB_print_error();
1264        return -1;
1265    }
1266
1267    GB_TEST_TRANSACTION(gbc);
1268    old_father = GB_FATHER(gbc);
1269
1270    if (GB_TYPE(gbc) != GB_DB) {
1271        GB_internal_error("GB_rename has to be called with container");
1272        return -1;
1273    }
1274
1275    gb_rename((GBCONTAINER*)gbc, new_key);
1276
1277    new_father = GB_FATHER(gbc);
1278    if (old_father != new_father) {
1279        GB_internal_error("father changed during rename");
1280        return -1;
1281    }
1282
1283    gb_touch_header(new_father);
1284    gb_touch_entry(gbc, gb_changed);
1285
1286    return 0;
1287}
1288
1289/* User accessible create, check everything */
1290GBDATA *GB_create(GBDATA *father,const char *key, GB_TYPES type)
1291{
1292    GBDATA *gbd;
1293
1294    if (GB_check_key(key)) {
1295        GB_print_error();
1296        return NULL;
1297    }
1298
1299    if (type == GB_DB) {
1300        gb_assert(type != GB_DB); // you like to use GB_create_container!
1301        GB_export_error("GB_create error: can't create containers");
1302        return NULL;
1303    }
1304
1305    /*     now checked by GB_check_key */
1306    /*     if ( (*key == '\0')) { */
1307    /*         GB_export_error("GB_create error: empty key"); */
1308    /*         return NULL; */
1309    /*     } */
1310
1311    if ( !father ) {
1312        GB_internal_errorf("GB_create error in GB_create:\nno father (key = '%s')",key);
1313        return NULL;
1314    }
1315    GB_TEST_TRANSACTION(father);
1316    if ( GB_TYPE(father)!=GB_DB) {
1317        GB_export_errorf("GB_create: father (%s) is not of GB_DB type (%i) (creating '%s')",
1318                         GB_read_key_pntr(father),GB_TYPE(father),key);
1319        return NULL;
1320    };
1321
1322    if (type == GB_POINTER) {
1323        if (!GB_in_temporary_branch(father)) {
1324            GB_export_error("GB_create: pointers only allowed in temporary branches");
1325            return NULL;
1326        }
1327    }
1328
1329    gbd = gb_make_entry((GBCONTAINER *)father, key, -1,0,type);
1330    gb_touch_header(GB_FATHER(gbd));
1331    gb_touch_entry(gbd,gb_created);
1332   
1333    gb_assert(GB_ARRAY_FLAGS(gbd).changed < gb_deleted); // happens sometimes -> needs debugging
1334   
1335    return gbd;
1336}
1337
1338GBDATA *GB_create_container(GBDATA *father,const char *key)
1339{
1340    /* create a new container */
1341   
1342    GBCONTAINER *gbd;
1343    if (GB_check_key(key)) {
1344        GB_print_error();
1345        return NULL;
1346    }
1347
1348    if ( (*key == '\0')) {
1349        GB_export_error("GB_create error: empty key");
1350        return NULL;
1351    }
1352    if ( !father ) {
1353        GB_internal_errorf("GB_create error in GB_create:\nno father (key = '%s')",key);
1354        return NULL;
1355    }
1356    GB_TEST_TRANSACTION(father);
1357    if ( GB_TYPE(father)!=GB_DB) {
1358        GB_export_errorf("GB_create: father (%s) is not of GB_DB type (%i) (creating '%s')",
1359                         GB_read_key_pntr(father),GB_TYPE(father),key);
1360        return NULL;
1361    };
1362    gbd = gb_make_container((GBCONTAINER *)father,key, -1, 0);
1363    gb_touch_header(GB_FATHER(gbd));
1364    gb_touch_entry((GBDATA *)gbd,gb_created);
1365    return (GBDATA *)gbd;
1366}
1367
1368#if defined(DEVEL_RALF)
1369#warning change param for GB_delete to GBDATA **
1370#endif /* DEVEL_RALF */
1371
1372GB_ERROR GB_delete(GBDATA *source) {
1373    GBDATA *gb_main;
1374
1375    GB_TEST_TRANSACTION(source);
1376    if (GB_GET_SECURITY_DELETE(source)>GB_MAIN(source)->security_level) {
1377        return GB_export_errorf("Security error in GB_delete: %s",GB_read_key_pntr(source));
1378    }
1379
1380    gb_main = GB_get_root(source);
1381
1382    if (source->flags.compressed_data) {
1383        GB_set_compression(gb_main, 0); /* disable compression */
1384        gb_set_compression(source); /* write data w/o compression (otherwise GB_read_old_value... won't work) */
1385        GB_set_compression(gb_main, -1); /* allow all types of compressions */
1386    }
1387
1388    {
1389        GB_MAIN_TYPE *Main = GB_MAIN(source);
1390        if (Main->transaction<0){
1391            gb_delete_entry(&source);
1392            gb_do_callback_list(Main);
1393        }
1394        else {
1395            gb_touch_entry(source,gb_deleted);
1396        }
1397    }
1398    return 0;
1399}
1400
1401/* int GB_entry_is_deleted(GBDATA *gb_entry) { */
1402/*     GBCONTAINER  *father      = gb_entry ? GB_FATHER(gb_entry) : 0; */
1403/*     GB_MAIN_TYPE *Main        = father ? GB_MAIN(gb_entry) : 0; */
1404/*     int           legal_entry = (father != 0) && (Main != 0); */
1405
1406/*     return !legal_entry; */
1407/* } */
1408
1409GB_ERROR gb_delete_force(GBDATA *source)    /* delete always */
1410{
1411    gb_touch_entry(source,gb_deleted);
1412    return 0;
1413}
1414
1415
1416/********************************************************************************************
1417                    Copy Data
1418********************************************************************************************/
1419
1420#if defined(DEVEL_RALF)
1421#warning replace GB_copy with GB_copy_with_protection after release
1422#endif /* DEVEL_RALF */
1423
1424GB_ERROR GB_copy(GBDATA *dest, GBDATA *source) {
1425    return GB_copy_with_protection(dest, source, GB_FALSE);
1426}
1427
1428GB_ERROR GB_copy_with_protection(GBDATA *dest, GBDATA *source, GB_BOOL copy_all_protections) {
1429    GB_TYPES type;
1430    GB_ERROR error = 0;
1431    GBDATA *gb_p;
1432    GBDATA *gb_d;
1433    GBCONTAINER *destc,*sourcec;
1434    const char *key;
1435
1436    GB_TEST_TRANSACTION(source);
1437    type = GB_TYPE(source);
1438    if (GB_TYPE(dest) != type)
1439    {
1440        return GB_export_errorf("incompatible types in GB_copy (source %s:%u != %s:%u",
1441                                GB_read_key_pntr(source), type, GB_read_key_pntr(dest), GB_TYPE(dest));
1442    }
1443
1444    switch (type)
1445    {
1446        case GB_INT:
1447            error = GB_write_int(dest,GB_read_int(source));
1448            break;
1449        case GB_FLOAT:
1450            error = GB_write_float(dest,GB_read_float(source));
1451            break;
1452        case GB_BYTE:
1453            error = GB_write_byte(dest,GB_read_byte(source));
1454            break;
1455        case GB_STRING:     /* No local compression */
1456            error = GB_write_string(dest,GB_read_char_pntr(source));
1457            break;
1458        case GB_LINK:       /* No local compression */
1459            error = GB_write_link(dest,GB_read_link_pntr(source));
1460            break;
1461        case GB_BITS:       /* only local compressions for the following types */
1462        case GB_BYTES:
1463        case GB_INTS:
1464        case GB_FLOATS:
1465            gb_save_extern_data_in_ts(dest);
1466            GB_SETSMDMALLOC(dest,   GB_GETSIZE(source),
1467                            GB_GETMEMSIZE(source),
1468                            GB_GETDATA(source));
1469            dest->flags.compressed_data = source->flags.compressed_data;
1470
1471            break;
1472        case GB_DB:
1473
1474            destc = (GBCONTAINER *)dest;
1475            sourcec = (GBCONTAINER *)source;
1476
1477            if (GB_TYPE(destc) != GB_DB)
1478            {
1479                GB_ERROR err = GB_export_errorf("GB_COPY Type conflict %s:%i != %s:%i",
1480                                                GB_read_key_pntr(dest), GB_TYPE(dest), GB_read_key_pntr(source), GB_DB);
1481                GB_internal_error(err);
1482                return err;
1483            }
1484
1485            if (source->flags2.folded_container)    gb_unfold((GBCONTAINER *)source,-1,-1);
1486            if (dest->flags2.folded_container)  gb_unfold((GBCONTAINER *)dest,0,-1);
1487
1488            for (gb_p = GB_child(source); gb_p; gb_p = GB_nextChild(gb_p)) {
1489                GB_TYPES type2 = (GB_TYPES)GB_TYPE(gb_p);
1490
1491                key = GB_read_key_pntr(gb_p);
1492                if (type2 == GB_DB)
1493                {
1494                    gb_d = GB_create_container(dest,key);
1495                    gb_create_header_array((GBCONTAINER *)gb_d, ((GBCONTAINER *)gb_p)->d.size);
1496                }
1497                else
1498                {
1499                    gb_d = GB_create(dest,key,type2);
1500                }
1501
1502                if (!gb_d) error = GB_await_error();
1503                else error       = GB_copy_with_protection(gb_d, gb_p, copy_all_protections);
1504               
1505                if (error) break;
1506            }
1507
1508            destc->flags3 = sourcec->flags3;
1509            break;
1510
1511        default:
1512            error = GB_export_error("GB_copy error unknown type");
1513    }
1514    if (error) return error;
1515
1516    gb_touch_entry(dest,gb_changed);
1517
1518    dest->flags.security_read = source->flags.security_read;
1519    if (copy_all_protections == GB_TRUE) {
1520        dest->flags.security_write  = source->flags.security_write;
1521        dest->flags.security_delete = source->flags.security_delete;
1522    }
1523
1524    return 0;
1525}
1526
1527/********************************************************************************************
1528                                        Get all subfield names
1529********************************************************************************************/
1530
1531static char *gb_stpcpy(char *dest, const char *source)
1532{
1533    while ((*dest++=*source++)) ;
1534    return dest-1; /* return pointer to last copied character (which is \0) */
1535}
1536
1537char* GB_get_subfields(GBDATA *gbd)
1538{
1539    long type;
1540    char *result = 0;
1541
1542    GB_TEST_TRANSACTION(gbd);
1543    type = GB_TYPE(gbd);
1544
1545    if (type==GB_DB) { /* we are a container */
1546        GBCONTAINER *gbc = (GBCONTAINER*)gbd;
1547        GBDATA *gbp;
1548        int result_length = 0;
1549
1550        if (gbc->flags2.folded_container) {
1551            gb_unfold(gbc, -1, -1);
1552        }
1553
1554        for (gbp = GB_child(gbd); gbp; gbp = GB_nextChild(gbp)) {
1555            const char *key = GB_read_key_pntr(gbp);
1556            int keylen = strlen(key);
1557
1558            if (result) {
1559                char *neu_result = (char*)malloc(result_length+keylen+1+1);
1560
1561                if (neu_result) {
1562                    char *p = gb_stpcpy(neu_result, result);
1563                    p = gb_stpcpy(p, key);
1564                    *p++ = ';';
1565                    p[0] = 0;
1566
1567                    freeset(result, neu_result);
1568                    result_length += keylen+1;
1569                }
1570                else {
1571                    gb_assert(0);
1572                }
1573            }
1574            else {
1575                result = (char*)malloc(1+keylen+1+1);
1576                result[0] = ';';
1577                strcpy(result+1, key);
1578                result[keylen+1] = ';';
1579                result[keylen+2] = 0;
1580                result_length = keylen+2;
1581            }
1582        }
1583    }
1584    else {
1585        result = strdup(";");
1586    }
1587
1588    return result;
1589}
1590
1591/********************************************************************************************
1592                    Copy Data
1593********************************************************************************************/
1594GB_ERROR gb_set_compression(GBDATA *source)
1595{
1596    long type;
1597    GB_ERROR error = 0;
1598    GBDATA *gb_p;
1599    char *string;
1600
1601    GB_TEST_TRANSACTION(source);
1602    type = GB_TYPE(source);
1603
1604    switch (type) {
1605        case GB_STRING:
1606            string = GB_read_string(source);
1607            GB_write_string(source,"");
1608            GB_write_string(source,string);
1609            free(string);
1610            break;
1611        case GB_BITS:
1612        case GB_BYTES:
1613        case GB_INTS:
1614        case GB_FLOATS:
1615            break;
1616        case GB_DB:
1617            for (gb_p = GB_child(source); gb_p; gb_p = GB_nextChild(gb_p)) {
1618                error = gb_set_compression(gb_p);
1619                if (error) break;
1620            }
1621            break;
1622        default:
1623            break;
1624    }
1625    if (error) return error;
1626    return 0;
1627}
1628
1629GB_ERROR GB_set_compression(GBDATA *gb_main, GB_COMPRESSION_MASK disable_compression){
1630    GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
1631    GB_ERROR error = 0;
1632    if (Main->compression_mask == disable_compression) return 0;
1633    Main->compression_mask = disable_compression;
1634#if 0
1635    GB_push_my_security(gb_main);
1636    error = gb_set_compression(gb_main);
1637    GB_pop_my_security(gb_main);
1638#endif
1639    return error;
1640}
1641
1642
1643
1644/********************************************************************************************
1645                    TEMPORARY
1646********************************************************************************************/
1647
1648
1649/** if the temporary flag is set, then that entry (including all subentries) will not be saved*/
1650GB_ERROR GB_set_temporary(GBDATA *gbd)
1651{
1652    GB_TEST_TRANSACTION(gbd);
1653    if (GB_GET_SECURITY_DELETE(gbd)>GB_MAIN(gbd)->security_level)
1654        return GB_export_errorf("Security error in GB_set_temporary: %s",GB_read_key_pntr(gbd));
1655    gbd->flags.temporary = 1;
1656    gb_touch_entry(gbd,gb_changed);
1657    return 0;
1658}
1659
1660/** enable save */
1661GB_ERROR GB_clear_temporary(GBDATA *gbd)
1662{
1663    GB_TEST_TRANSACTION(gbd);
1664    gbd->flags.temporary = 0;
1665    gb_touch_entry(gbd,gb_changed);
1666    return 0;
1667}
1668
1669GB_BOOL GB_is_temporary(GBDATA *gbd) {
1670    GB_TEST_TRANSACTION(gbd);
1671    return (long)gbd->flags.temporary;
1672}
1673
1674GB_BOOL GB_in_temporary_branch(GBDATA *gbd) {
1675    // returns true, if 'gbd' is member of a temporary subtree
1676
1677    if (GB_is_temporary(gbd)) return GB_TRUE;
1678
1679    GBDATA *gb_parent = GB_get_father(gbd);
1680    if (!gb_parent) return GB_FALSE;
1681
1682    return GB_in_temporary_branch(gb_parent);
1683}
1684
1685
1686/********************************************************************************************
1687                    TRANSACTIONS
1688********************************************************************************************/
1689
1690GB_ERROR GB_push_local_transaction(GBDATA *gbd) {
1691    /* Starts a read only transaction !!;
1692       be sure that all data is cached
1693       be extremely careful !!!!! */
1694   
1695    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1696    if (Main->transaction>0) {
1697        return GB_push_transaction(gbd);
1698    }
1699    Main->transaction --;
1700    return 0;
1701}
1702
1703GB_ERROR GB_pop_local_transaction(GBDATA *gbd) {
1704    /* Stops a read only transaction !!; be sure that all data is cached !!!!! */
1705    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1706    if (Main->transaction>0){
1707        return GB_pop_transaction(gbd);
1708    }
1709    Main->transaction ++;
1710    return 0;
1711}
1712
1713/*
1714 * recommended transaction usage:
1715 * ------------------------------
1716 *
1717 * GB_ERROR myFunc() {
1718 *     GB_ERROR error = GB_push_transaction(gbd);
1719 *     if (!error) {
1720 *         error = ...;
1721 *     }
1722 *     return GB_end_transaction(gbd, error);
1723 * }
1724 *       
1725 * void myFunc() {
1726 *     GB_ERROR error = GB_push_transaction(gbd);
1727 *     if (!error) {
1728 *         error = ...;
1729 *     }
1730 *     GB_end_transaction_show_error(gbd, error, aw_message);
1731 * }
1732 */
1733
1734GB_ERROR GB_push_transaction(GBDATA *gbd){
1735    /* start a transaction if no transaction is running */
1736
1737    GB_MAIN_TYPE *Main  = GB_MAIN(gbd);
1738    GB_ERROR      error = 0;
1739
1740    if (Main->transaction == 0) error = GB_begin_transaction(gbd);
1741    else if (Main->transaction>0) Main->transaction++;
1742    // Main->transaction<0 is "no transaction mode"
1743
1744    return error;
1745}
1746
1747GB_ERROR GB_pop_transaction(GBDATA *gbd) {
1748    GB_ERROR error;
1749    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1750    if (Main->transaction==0) {
1751        error = GB_export_error("Pop without push");
1752        GB_internal_error(error);
1753        return  error;
1754    }
1755    if (Main->transaction<0) return 0;  /* no transaction mode */
1756    if (Main->transaction==1){
1757        return GB_commit_transaction(gbd);
1758    }else{
1759        Main->transaction--;
1760    }
1761    return 0;
1762}
1763
1764GB_ERROR GB_begin_transaction(GBDATA *gbd) {
1765    // better use GB_push_transaction()
1766   
1767    GB_ERROR      error;
1768    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1769    gbd                = (GBDATA *)Main->data;
1770    if (Main->transaction>0) {
1771        error = GB_export_errorf("GB_begin_transaction called %i !!!",
1772                                 Main->transaction);
1773        GB_internal_error(error);
1774        return GB_push_transaction(gbd);
1775    }
1776    if (Main->transaction<0) return 0;
1777    Main->transaction = 1;
1778    Main->aborted_transaction = 0;
1779    if (!Main->local_mode){
1780        error = gbcmc_begin_transaction(gbd);
1781        if (error) return error;
1782        error = gb_commit_transaction_local_rek(gbd,0,0);   /* init structures */
1783        gb_untouch_children((GBCONTAINER *)gbd);
1784        gb_untouch_me(gbd);
1785        if (error) return error;
1786    }
1787
1788    /* do all callbacks
1789     * cb that change the db are no problem, because it's the beginning of a ta
1790     */
1791    gb_do_callback_list(Main);
1792   
1793    Main->clock ++;
1794    return 0;
1795}
1796
1797GB_ERROR gb_init_transaction(GBCONTAINER *gbd)      /* the first transaction ever */
1798{
1799    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1800    GB_ERROR      error;
1801
1802    Main->transaction = 1;
1803   
1804    error = gbcmc_init_transaction(Main->data);
1805    if (!error) Main->clock ++;
1806
1807    return error;
1808}
1809
1810GB_ERROR GB_no_transaction(GBDATA *gbd)
1811{
1812    GB_ERROR error;
1813    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1814    if (!Main->local_mode) {
1815        error = GB_export_error("Tried to disable transactions in a client");
1816        GB_internal_error(error);
1817        return 0;
1818    }
1819    Main->transaction = -1;
1820    return 0;
1821}
1822
1823GB_ERROR GB_abort_transaction(GBDATA *gbd)
1824{
1825    GB_ERROR error;
1826    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1827    gbd = (GBDATA *)Main->data;
1828    if (Main->transaction<=0) {
1829        GB_internal_error("No running Transaction");
1830        return GB_export_error("GB_abort_transaction: No running Transaction");
1831    }
1832    if (Main->transaction>1) {
1833        Main->aborted_transaction = 1;
1834        return GB_pop_transaction(gbd);
1835    }
1836
1837    gb_abort_transaction_local_rek(gbd,0);
1838    if (!Main->local_mode){
1839        error = gbcmc_abort_transaction(gbd);
1840        if (error) return error;
1841    }
1842    Main->clock--;
1843    gb_do_callback_list(Main);       /* do all callbacks */
1844    Main->transaction = 0;
1845    gb_untouch_children((GBCONTAINER *)gbd);
1846    gb_untouch_me(gbd);
1847    return 0;
1848}
1849
1850GB_ERROR GB_commit_transaction(GBDATA *gbd) {
1851    GB_ERROR      error = 0;
1852    GB_MAIN_TYPE *Main  = GB_MAIN(gbd);
1853    GB_CHANGED    flag;
1854
1855    gbd = (GBDATA *)Main->data;
1856    if (!Main->transaction) {
1857        error = GB_export_error("GB_commit_transaction: No running Transaction");
1858        GB_internal_error(error);
1859        return error;
1860    }
1861    if (Main->transaction>1){
1862        GB_internal_error("Running GB_commit_transaction not at root transaction level");
1863        return GB_pop_transaction(gbd);
1864    }
1865    if (Main->aborted_transaction) {
1866        Main->aborted_transaction = 0;
1867        return      GB_abort_transaction(gbd);
1868    }
1869    if (Main->local_mode) {
1870        char *error1 = gb_set_undo_sync(gbd);
1871        while(1){
1872            flag = (GB_CHANGED)GB_ARRAY_FLAGS(gbd).changed;
1873            if (!flag) break;           /* nothing to do */
1874            error = gb_commit_transaction_local_rek(gbd,0,0);
1875            gb_untouch_children((GBCONTAINER *)gbd);
1876            gb_untouch_me(gbd);
1877            if (error) break;
1878            gb_do_callback_list(Main);       /* do all callbacks */
1879        }
1880        gb_disable_undo(gbd);
1881        if(error1){
1882            Main->transaction = 0;
1883            return error;
1884        }
1885    }else{
1886        gb_disable_undo(gbd);
1887        while(1){
1888            flag = (GB_CHANGED)GB_ARRAY_FLAGS(gbd).changed;
1889            if (!flag) break;           /* nothing to do */
1890
1891            error = gbcmc_begin_sendupdate(gbd);        if (error) break;
1892            error = gb_commit_transaction_local_rek(gbd,1,0);   if (error) break;
1893            error = gbcmc_end_sendupdate(gbd);      if (error) break;
1894
1895            gb_untouch_children((GBCONTAINER *)gbd);
1896            gb_untouch_me(gbd);
1897            gb_do_callback_list(Main);       /* do all callbacks */
1898        }
1899        if (!error) error = gbcmc_commit_transaction(gbd);
1900
1901    }
1902    Main->transaction = 0;
1903    if (error) return error;
1904    return 0;
1905}
1906
1907GB_ERROR GB_end_transaction(GBDATA *gbd, GB_ERROR error) {
1908    if (error) GB_abort_transaction(gbd);
1909    else error = GB_pop_transaction(gbd);
1910    return error;
1911}
1912
1913void GB_end_transaction_show_error(GBDATA *gbd, GB_ERROR error, void (*error_handler)(GB_ERROR)) {
1914    error = GB_end_transaction(gbd, error);
1915    if (error) error_handler(error);
1916}
1917
1918int GB_get_transaction_level(GBDATA *gbd) {
1919    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
1920    return Main->transaction;
1921}
1922
1923/********************************************************************************************
1924            Send updated data to server (for GB_release)
1925********************************************************************************************/
1926GB_ERROR GB_update_server(GBDATA *gbd)
1927{
1928    GB_ERROR error;
1929    GB_MAIN_TYPE    *Main = GB_MAIN(gbd);
1930    GBDATA *gb_main = (GBDATA *)Main->data;
1931    struct gb_callback_list *cbl_old = Main->cbl_last;
1932    if (!Main->transaction) {
1933        error = GB_export_error("GB_update_server: No running Transaction");
1934        GB_internal_error(error);
1935        return error;
1936    }
1937    if (Main->local_mode){
1938        return GB_export_error("You cannot update the server as you are the server yourself");
1939    }
1940
1941    error = gbcmc_begin_sendupdate(gb_main);
1942    if (error) return error;
1943    error = gb_commit_transaction_local_rek(gbd,2,0);
1944    if (error) return error;
1945    error = gbcmc_end_sendupdate(gb_main);
1946    if (error) return error;
1947    if (cbl_old != Main->cbl_last){
1948        GB_internal_error("GB_update_server produced a callback, this is not allowed");
1949    }
1950    /* gb_do_callback_list(gbd);         do all callbacks  */
1951    return 0;
1952}
1953/********************************************************************************************
1954                    CALLBACKS
1955********************************************************************************************/
1956
1957GB_ERROR gb_add_changed_callback_list(GBDATA *gbd,struct gb_transaction_save *old, GB_CB_TYPE gbtype, GB_CB func, int *clientdata)
1958{
1959    struct gb_callback_list *cbl;
1960    GB_MAIN_TYPE    *Main = GB_MAIN(gbd);
1961    cbl = (struct gb_callback_list *)gbm_get_mem(sizeof(struct gb_callback_list),GBM_CB_INDEX);
1962    if (Main->cbl){
1963        Main->cbl_last->next = cbl;
1964    }else{
1965        Main->cbl = cbl;
1966    }
1967    Main->cbl_last = cbl;
1968    cbl->clientdata = clientdata;
1969    cbl->func = func;
1970    cbl->gbd = gbd;
1971    cbl->type = gbtype;
1972    gb_add_ref_gb_transaction_save(old);
1973    cbl->old = old;
1974
1975    return 0;
1976}
1977
1978GB_ERROR gb_add_delete_callback_list(GBDATA *gbd,struct gb_transaction_save *old, GB_CB func, int *clientdata)
1979{
1980    struct gb_callback_list *cbl;
1981    GB_MAIN_TYPE    *Main = GB_MAIN(gbd);
1982    cbl = (struct gb_callback_list *)gbm_get_mem(sizeof(struct gb_callback_list),GBM_CB_INDEX);
1983    if (Main->cbld){
1984        Main->cbld_last->next = cbl;
1985    }else{
1986        Main->cbld = cbl;
1987    }
1988    Main->cbld_last = cbl;
1989    cbl->clientdata = clientdata;
1990    cbl->func = func;
1991    cbl->gbd = gbd;
1992    cbl->type = GB_CB_DELETE;
1993    if (old) gb_add_ref_gb_transaction_save(old);
1994    cbl->old = old;
1995    return 0;
1996}
1997
1998static struct gb_callback_list *g_b_old_callback_list = NULL; // points to callback during callback (NULL otherwise)
1999static GB_MAIN_TYPE            *g_b_old_main          = NULL; // points to DB root during callback (NULL otherwise)
2000
2001GB_ERROR gb_do_callback_list(GB_MAIN_TYPE *Main) {
2002    struct gb_callback_list *cbl,*cbl_next;
2003    g_b_old_main = Main;
2004
2005    /* first all delete callbacks: */
2006    for (cbl = Main->cbld; cbl ; cbl = cbl_next){
2007        g_b_old_callback_list = cbl;
2008        cbl->func(cbl->gbd,cbl->clientdata, GB_CB_DELETE);
2009        cbl_next = cbl->next;
2010        g_b_old_callback_list = NULL;
2011        gb_del_ref_gb_transaction_save(cbl->old);
2012        gbm_free_mem((char *)cbl,sizeof(struct gb_callback_list),GBM_CB_INDEX);
2013    }
2014   
2015    Main->cbld_last = NULL;
2016    Main->cbld      = NULL;
2017
2018    /* then all update callbacks: */
2019    for (cbl = Main->cbl; cbl ; cbl = cbl_next){
2020        g_b_old_callback_list = cbl;
2021        cbl->func(cbl->gbd,cbl->clientdata, cbl->type);
2022        cbl_next = cbl->next;
2023        g_b_old_callback_list = NULL;
2024        gb_del_ref_gb_transaction_save(cbl->old);
2025        gbm_free_mem((char *)cbl,sizeof(struct gb_callback_list),GBM_CB_INDEX);
2026    }
2027
2028    g_b_old_main   = NULL;
2029    Main->cbl_last = NULL;
2030    Main->cbl      = NULL;
2031   
2032    return 0;
2033}
2034
2035GB_MAIN_TYPE *gb_get_main_during_cb() {
2036    /* if inside a callback, return the DB root of the DB element, the callback was called for.
2037     * if not inside a callback, return NULL.
2038     */
2039    return g_b_old_main;
2040}
2041
2042NOT4PERL GB_BOOL GB_inside_callback(GBDATA *of_gbd, enum gb_call_back_type cbtype) {
2043    GB_MAIN_TYPE *Main   = gb_get_main_during_cb();
2044    GB_BOOL       inside = GB_FALSE;
2045
2046    if (Main) {                 // inside a callback
2047        gb_assert(g_b_old_callback_list);
2048        if (g_b_old_callback_list->gbd == of_gbd) {
2049            GB_CB_TYPE curr_cbtype;
2050            if (Main->cbld) {       // delete callbacks were not all performed yet
2051                                    // -> current callback is a delete callback
2052                curr_cbtype = g_b_old_callback_list->type & GB_CB_DELETE;
2053            }
2054            else {
2055                gb_assert(Main->cbl); // change callback
2056                curr_cbtype = g_b_old_callback_list->type & (GB_CB_ALL-GB_CB_DELETE);
2057            }
2058            gb_assert(curr_cbtype != GB_CB_NONE); // wtf!? are we inside callback or not?
2059
2060            if ((cbtype&curr_cbtype) != GB_CB_NONE) {
2061                inside = GB_TRUE;
2062            }
2063        }
2064    }
2065
2066    return inside;
2067}
2068
2069GBDATA *GB_get_gb_main_during_cb() {
2070    GBDATA       *gb_main = NULL;
2071    GB_MAIN_TYPE *Main    = gb_get_main_during_cb();
2072
2073    if (Main) {                 // inside callback
2074        if (!GB_inside_callback((GBDATA*)Main->data, GB_CB_DELETE)) { // main is not deleted
2075            gb_main = (GBDATA*)Main->data;
2076        }
2077    }
2078    return gb_main;
2079}
2080
2081
2082
2083GB_CSTR gb_read_pntr_ts(GBDATA *gbd, struct gb_transaction_save *ts){
2084    int         type = GB_TYPE_TS(ts);
2085    const char *data = GB_GETDATA_TS(ts);
2086    if (data) {
2087        if (ts->flags.compressed_data) {    /* uncompressed data return pntr to database entry   */
2088            long size = GB_GETSIZE_TS(ts) * gb_convert_type_2_sizeof[type] + gb_convert_type_2_appendix_size[type];
2089            data = gb_uncompress_data(gbd,data,size);
2090        }
2091    }
2092    return data;
2093}
2094
2095/* get last array value in callbacks */
2096NOT4PERL const void *GB_read_old_value(){
2097    char *data;
2098
2099    if (!g_b_old_callback_list) {
2100        GB_export_error("You cannot call GB_read_old_value outside a ARBDB callback");
2101        return NULL;
2102    }
2103    if (!g_b_old_callback_list->old) {
2104        GB_export_error("No old value available in GB_read_old_value");
2105        return NULL;
2106    }
2107    data = GB_GETDATA_TS(g_b_old_callback_list->old);
2108    if (!data) return NULL;
2109
2110    return gb_read_pntr_ts(g_b_old_callback_list->gbd, g_b_old_callback_list->old);
2111}
2112/* same for size */
2113long GB_read_old_size(){
2114    if (!g_b_old_callback_list) {
2115        GB_export_error("You cannot call GB_read_old_size outside a ARBDB callback");
2116        return -1;
2117    }
2118    if (!g_b_old_callback_list->old) {
2119        GB_export_error("No old value available in GB_read_old_size");
2120        return -1;
2121    }
2122    return GB_GETSIZE_TS(g_b_old_callback_list->old);
2123}
2124
2125/********************************************************************************************
2126                    CALLBACKS
2127********************************************************************************************/
2128
2129char *GB_get_callback_info(GBDATA *gbd) {
2130    /* returns human-readable information about callbacks of 'gbd' or 0 */
2131    char *result = 0;
2132    if (gbd->ext) {
2133        struct gb_callback *cb = gbd->ext->callback;
2134        while (cb) {
2135            char *cb_info = GBS_global_string_copy("func=%p type=%i clientdata=%p priority=%i",
2136                                                   (void*)cb->func, cb->type, cb->clientdata, cb->priority);
2137            if (result) {
2138                char *new_result = GBS_global_string_copy("%s\n%s", result, cb_info);
2139                free(result);
2140                free(cb_info);
2141                result = new_result;
2142            }
2143            else {
2144                result = cb_info;
2145            }
2146            cb = cb->next;
2147        }
2148    }
2149
2150    return result;
2151}
2152
2153GB_ERROR GB_add_priority_callback(GBDATA *gbd, enum gb_call_back_type type, GB_CB func, int *clientdata, int priority) {
2154    /* Adds a callback to a DB entry.
2155     *
2156     * Callbacks with smaller priority values get executed before bigger priority values.
2157     *
2158     * Be careful when writing GB_CB_DELETE callbacks, there is a severe restriction:
2159     *
2160     * - the DB element may already be freed. The pointer is still pointing to the original
2161     *   location, so you can use it to identify the DB element, but you cannot dereference
2162     *   it under all circumstances.
2163     *
2164     * ARBDB internal delete-callbacks may use gb_get_main_during_cb() to access the DB root.
2165     * See also: GB_get_gb_main_during_cb()
2166     */
2167
2168    struct gb_callback *cb;
2169
2170#if defined(DEBUG)
2171    if (GB_inside_callback(gbd, GB_CB_DELETE)) {
2172        printf("Warning: GB_add_priority_callback called inside delete-callback of gbd (gbd may already be freed)\n");
2173#if defined(DEVEL_RALF)
2174        gb_assert(0); // fix callback-handling (never modify callbacks from inside delete callbacks)
2175#endif /* DEVEL_RALF */
2176    }
2177#endif /* DEBUG */
2178
2179    GB_TEST_TRANSACTION(gbd); // may return error
2180    GB_CREATE_EXT(gbd);
2181    cb = (struct gb_callback *)gbm_get_mem(sizeof(struct gb_callback),GB_GBM_INDEX(gbd));
2182
2183    if (gbd->ext->callback) {
2184        struct gb_callback *prev = 0;
2185        struct gb_callback *curr = gbd->ext->callback;
2186
2187        while (curr) {
2188            if (priority <= curr->priority) {
2189                // wanted priority is lower -> insert here
2190                break;
2191            }
2192
2193#if defined(DEVEL_RALF)
2194            // test if callback already was added (every callback shall only exist once). see below.
2195            gb_assert((curr->func != func) || (curr->clientdata != clientdata) || (curr->type != type ));
2196#endif /* DEVEL_RALF */
2197
2198            prev = curr;
2199            curr = curr->next;
2200        }
2201
2202        if (prev) { prev->next = cb; }
2203        else { gbd->ext->callback = cb; }
2204
2205        cb->next = curr;
2206    }
2207    else {
2208        cb->next           = 0;
2209        gbd->ext->callback = cb;
2210    }
2211
2212    cb->type       = type;
2213    cb->clientdata = clientdata;
2214    cb->func       = func;
2215    cb->priority   = priority;
2216
2217#if defined(DEVEL_RALF)
2218#if defined(DEBUG)
2219    // test if callback already was added (every callback shall only exist once)
2220    // maybe you like to use GB_ensure_callback instead of GB_add_callback
2221    while (cb->next) {
2222        cb = cb->next;
2223        gb_assert((cb->func != func) || (cb->clientdata != clientdata) || (cb->type != type ));
2224    }
2225#endif /* DEBUG */
2226#endif /* DEVEL_RALF */
2227
2228    return 0;
2229}
2230
2231GB_ERROR GB_add_callback(GBDATA *gbd, enum gb_call_back_type type, GB_CB func, int *clientdata) {
2232    return GB_add_priority_callback(gbd, type, func, clientdata, 5); // use default priority 5
2233}
2234
2235static void gb_remove_callback(GBDATA *gbd, enum gb_call_back_type type, GB_CB func, int *clientdata, GB_BOOL cd_should_match) {
2236    GB_BOOL removed     = GB_FALSE;
2237    GB_BOOL exactly_one = cd_should_match; // remove exactly one callback
2238
2239#if defined(DEBUG)
2240    if (GB_inside_callback(gbd, GB_CB_DELETE)) {
2241        printf("Warning: gb_remove_callback called inside delete-callback of gbd (gbd may already be freed)\n");
2242#if defined(DEVEL_RALF)
2243        gb_assert(0); // fix callback-handling (never modify callbacks from inside delete callbacks)
2244#endif /* DEVEL_RALF */
2245    }
2246#endif /* DEBUG */
2247
2248    if (gbd->ext) {
2249        struct gb_callback **cb_ptr       = &gbd->ext->callback;
2250        struct gb_callback  *cb;
2251        short                prev_running = 0;
2252
2253        for (cb = *cb_ptr; cb; cb = *cb_ptr) {
2254            short this_running = cb->running;
2255
2256            if ((cb->func == func)  &&
2257                (cb->type == type ) &&
2258                (cb->clientdata == clientdata || !cd_should_match))
2259            {
2260                if (prev_running || cb->running) {
2261                    // if the previous callback in list or the callback itself is running (in "no transaction mode")
2262                    // the callback cannot be removed (see gb_do_callbacks)
2263                    GBK_terminate("gb_remove_callback: tried to remove currently running callback");
2264                }
2265
2266                *cb_ptr = cb->next;
2267                gbm_free_mem((char *)cb,sizeof(struct gb_callback),GB_GBM_INDEX(gbd));
2268                removed = GB_TRUE;
2269                if (exactly_one) break;
2270            }
2271            else {
2272                cb_ptr = &cb->next;
2273            }
2274            prev_running = this_running;
2275        }
2276    }
2277}
2278
2279void GB_remove_callback(GBDATA *gbd, enum gb_call_back_type type, GB_CB func, int *clientdata) {
2280    // remove specific callback (type, func and clientdata must match)
2281    gb_remove_callback(gbd, type, func, clientdata, GB_TRUE);
2282}
2283
2284void GB_remove_all_callbacks_to(GBDATA *gbd, enum gb_call_back_type type, GB_CB func) {
2285    // removes all callbacks 'func' bound to 'gbd' with 'type'
2286    gb_remove_callback(gbd, type, func, 0, GB_FALSE);
2287}
2288
2289GB_ERROR GB_ensure_callback(GBDATA *gbd, enum gb_call_back_type type, GB_CB func, int *clientdata) {
2290    struct gb_callback *cb;
2291    for (cb = GB_GET_EXT_CALLBACKS(gbd); cb; cb = cb->next) {
2292        if ((cb->func == func) && (cb->clientdata == clientdata) && (cb->type == type )) {
2293            return NULL;        /* already in cb list */
2294        }
2295    }
2296    return GB_add_callback(gbd,type,func,clientdata);
2297}
2298
2299/********************************************************************************************
2300                    RELEASE
2301    free cached data in a client, no pointers in the freed region are allowed
2302********************************************************************************************/
2303GB_ERROR GB_release(GBDATA *gbd){
2304    GBCONTAINER  *gbc;
2305    GBDATA       *gb;
2306    int           index;
2307    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
2308
2309    GB_TEST_TRANSACTION(gbd);
2310    if (Main->local_mode) return 0;
2311    if (GB_ARRAY_FLAGS(gbd).changed &&!gbd->flags2.update_in_server) {
2312        GB_update_server(gbd);
2313    }
2314    if (GB_TYPE(gbd) != GB_DB) {
2315        GB_ERROR error = GB_export_errorf("You cannot release non container (%s)",
2316                                          GB_read_key_pntr(gbd));
2317        GB_internal_error(error);
2318        return error;
2319    }
2320    if (gbd->flags2.folded_container) return 0;
2321    gbc = (GBCONTAINER *)gbd;
2322
2323    for (index = 0; index < gbc->d.nheader; index++) {
2324        if ( (gb = GBCONTAINER_ELEM(gbc,index)) ) {
2325            gb_delete_entry(&gb);
2326        }
2327    }
2328
2329    gbc->flags2.folded_container = 1;
2330    gb_do_callback_list(Main);       /* do all callbacks */
2331    return 0;
2332}
2333/********************************************************************************************
2334                    test local
2335    test whether data is available in local data
2336    !!! important for callbacks, because only testlocal tested data is available
2337********************************************************************************************/
2338
2339int GB_testlocal(GBDATA *gbd)
2340{
2341    if (GB_TYPE(gbd) != GB_DB) {
2342        return 1;           /* all non containers are available */
2343    }
2344    if (GB_MAIN(gbd)->local_mode) return 1;
2345    if (gbd->flags2.folded_container) return 0;
2346    return 1;
2347}
2348/********************************************************************************************
2349                    some information about sons
2350********************************************************************************************/
2351
2352int GB_nsons(GBDATA *gbd) {
2353    if (GB_TYPE(gbd) != GB_DB) {
2354        return 0;           /* all non containers are available */
2355    }
2356    return ((GBCONTAINER *)gbd)->d.size;
2357}
2358
2359void GB_disable_quicksave(GBDATA *gbd,const char *reason) {
2360    freedup(GB_MAIN(gbd)->qs.quick_save_disabled, reason);
2361}
2362/********************************************************************************************
2363                    Resort data base
2364********************************************************************************************/
2365
2366GB_ERROR GB_resort_data_base(GBDATA *gb_main, GBDATA **new_order_list, long listsize)
2367{
2368    long new_index;
2369    GBCONTAINER *father;
2370    struct gb_header_list_struct *hl, h;
2371
2372    if (GB_read_clients(gb_main)<0)
2373        return GB_export_error("Sorry: this program is not the arbdb server, you cannot resort your data");
2374
2375    if (GB_read_clients(gb_main)>0)
2376        return GB_export_errorf("There are %li clients (editors, tree programs) connected to this server,\n"
2377                                "please close clients and rerun operation",
2378                                GB_read_clients(gb_main));
2379
2380    if (listsize <=0) return 0;
2381
2382    father = GB_FATHER(new_order_list[0]);
2383    GB_disable_quicksave(gb_main,"some entries in the database got a new order");
2384    hl = GB_DATA_LIST_HEADER(father->d);
2385
2386    for (new_index= 0 ; new_index< listsize; new_index++ )
2387    {
2388        long old_index = new_order_list[new_index]->index;
2389
2390        if (old_index < new_index)
2391            GB_warningf("Warning at resort database: entry exists twice: %li and %li",
2392                        old_index, new_index);
2393        else
2394        {
2395            GBDATA *ngb;
2396            GBDATA *ogb;
2397            ogb = GB_HEADER_LIST_GBD(hl[old_index]);
2398            ngb = GB_HEADER_LIST_GBD(hl[new_index]);
2399
2400            h = hl[new_index];
2401            hl[new_index] = hl[old_index];
2402            hl[old_index] = h;              /* Warning: Relative Pointers are incorrect !!! */
2403
2404            SET_GB_HEADER_LIST_GBD(hl[old_index], ngb );
2405            SET_GB_HEADER_LIST_GBD(hl[new_index], ogb );
2406
2407            if ( ngb )  ngb->index = old_index;
2408            if ( ogb )  ogb->index = new_index;
2409        }
2410    }
2411
2412    gb_touch_entry((GBDATA *)father,gb_changed);
2413    return 0;
2414}
2415
2416GB_ERROR GB_resort_system_folder_to_top(GBDATA *gb_main){
2417    GBDATA *gb_system = GB_entry(gb_main,GB_SYSTEM_FOLDER);
2418    GBDATA *gb_first = GB_child(gb_main);
2419    GBDATA **new_order_list;
2420    GB_ERROR error = 0;
2421    int i,len;
2422    if (GB_read_clients(gb_main)<0) return 0; /* we are not server */
2423    if (!gb_system){
2424        return GB_export_error("System databaseentry does not exist");
2425    }
2426    if (gb_first == gb_system) return 0;
2427    len = GB_number_of_subentries(gb_main);
2428    new_order_list = (GBDATA **)GB_calloc(sizeof(GBDATA *),len);
2429    new_order_list[0] = gb_system;
2430    for (i=1;i<len;i++){
2431        new_order_list[i] = gb_first;
2432        do {
2433            gb_first = GB_nextChild(gb_first);
2434        } while(gb_first == gb_system);
2435    }
2436    error = GB_resort_data_base(gb_main,new_order_list,len);
2437    free(new_order_list);
2438    return error;
2439}
2440
2441/********************************************************************************************
2442                    USER FLAGS
2443********************************************************************************************/
2444GB_ERROR GB_write_usr_public(GBDATA *gbd, long flags)
2445{
2446    GB_TEST_TRANSACTION(gbd);
2447    if (GB_GET_SECURITY_WRITE(gbd) > GB_MAIN(gbd)->security_level)
2448        return gb_security_error(gbd);
2449    gbd->flags.user_flags = flags;
2450    gb_touch_entry(gbd,gb_changed);
2451    return 0;
2452}
2453
2454long GB_read_usr_public(GBDATA *gbd)
2455{
2456    GB_TEST_TRANSACTION(gbd);
2457    return (long)gbd->flags.user_flags;
2458}
2459
2460/********************************************************************************************
2461    private user access
2462********************************************************************************************/
2463
2464long GB_read_usr_private(GBDATA *gbd) {
2465    GBCONTAINER *gbc = (GBCONTAINER *)gbd;
2466    if (GB_TYPE(gbc) != GB_DB) {
2467        GB_ERROR error = GB_export_errorf("GB_write_usr_private: not a container (%s)",GB_read_key_pntr(gbd));
2468        GB_internal_error(error);
2469        return 0;
2470    }
2471    return gbc->flags2.usr_ref;
2472}
2473
2474GB_ERROR GB_write_usr_private(GBDATA *gbd,long ref) {
2475    GBCONTAINER *gbc = (GBCONTAINER *)gbd;
2476    if (GB_TYPE(gbc) != GB_DB) {
2477        GB_ERROR error = GB_export_errorf("GB_write_usr_private: not a container (%s)",GB_read_key_pntr(gbd));
2478        GB_internal_error(error);
2479        return 0;
2480    }
2481    gbc->flags2.usr_ref = ref;
2482    return 0;
2483}
2484
2485/********************************************************************************************
2486            flag access
2487********************************************************************************************/
2488
2489GB_ERROR GB_write_flag(GBDATA *gbd,long flag)
2490{
2491    GBCONTAINER *gbc  = (GBCONTAINER *)gbd;
2492    int          prev;
2493    int          ubit = GB_MAIN(gbd)->users[0]->userbit;
2494
2495    GB_TEST_TRANSACTION(gbd);
2496
2497    prev = GB_ARRAY_FLAGS(gbc).flags;
2498    gbd->flags.saved_flags = prev;
2499
2500    if (flag){
2501        GB_ARRAY_FLAGS(gbc).flags |= ubit;
2502    }else{
2503        GB_ARRAY_FLAGS(gbc).flags &= ~ubit;
2504    }
2505    if (prev != (int)GB_ARRAY_FLAGS(gbc).flags) {
2506        gb_touch_entry(gbd,gb_changed);
2507        gb_touch_header(GB_FATHER(gbd));
2508        GB_DO_CALLBACKS(gbd);
2509    }
2510    return 0;
2511}
2512
2513int GB_read_flag(GBDATA *gbd)
2514{
2515    GB_TEST_TRANSACTION(gbd);
2516    if (GB_ARRAY_FLAGS(gbd).flags & GB_MAIN(gbd)->users[0]->userbit) return 1;
2517    else return 0;
2518}
2519
2520/********************************************************************************************
2521            touch entry
2522********************************************************************************************/
2523
2524void GB_touch(GBDATA *gbd) {
2525    GB_TEST_TRANSACTION(gbd);
2526    gb_touch_entry(gbd,gb_changed);
2527    GB_DO_CALLBACKS(gbd);
2528}
2529
2530
2531/********************************************************************************************
2532            debug data
2533********************************************************************************************/
2534
2535void dump(const char *data, int size)
2536{
2537    int x = 0;
2538
2539    printf("\nDump %p (%i Byte):\n", data, size);
2540
2541    while (size--)
2542    {
2543        const char *hex = "0123456789abcdef";
2544        char c = *data++;
2545
2546        printf("%c%c ", hex[(c&0xf0)>>4], hex[c&0x0f]);
2547
2548        if (++x==32)
2549        {
2550            x = 0;
2551            printf("\n");
2552        }
2553    }
2554
2555    printf("\n");
2556}
2557
2558GB_ERROR GB_print_debug_information(void *dummy, GBDATA *gb_main){
2559    int i;
2560    GB_MAIN_TYPE *Main = GB_MAIN( gb_main );
2561    GB_push_transaction(gb_main);
2562    dummy = dummy;
2563    for (i=0;i<Main->keycnt;i++) {
2564        if (Main->keys[i].key) {
2565            printf("%3i %20s    nref %i\n", i, Main->keys[i].key, (int)Main->keys[i].nref);
2566        }else{
2567            printf("    %3i unused key, next free key = %li\n", i, Main->keys[i].next_free_key);
2568        }
2569    }
2570    gbm_debug_mem(Main);
2571    GB_pop_transaction(gb_main);
2572    return 0;
2573}
2574
2575int GB_info_deep = 15;
2576
2577
2578int gb_info(GBDATA *gbd, int deep){
2579    GBCONTAINER *gbc;
2580    GB_TYPES type;
2581    char    *data;
2582    int     size ;
2583    GB_MAIN_TYPE *Main;
2584
2585    if (gbd==NULL) { printf("NULL\n"); return -1; }
2586    GB_push_transaction(gbd);
2587    type = (GB_TYPES)GB_TYPE(gbd);
2588
2589    if (deep) {
2590        printf("    ");
2591    }
2592
2593    printf("(GBDATA*)0x%lx (GBCONTAINER*)0x%lx ",(long)gbd,(long)gbd);
2594
2595    if (gbd->rel_father==0) { printf("father=NULL\n"); return -1; }
2596
2597    if (type==GB_DB)    {gbc = (GBCONTAINER*) gbd; Main = GBCONTAINER_MAIN(gbc);}
2598    else        {gbc = NULL; Main = GB_MAIN(gbd);}
2599
2600    if (!Main)                  { printf("Oops - I have no main entry!!!\n"); return -1;}
2601    if (gbd==(GBDATA*)(Main->dummy_father))     { printf("dummy_father!\n"); return -1; }
2602
2603    printf("%10s Type '%c'  ", GB_read_key_pntr(gbd), GB_TYPE_2_CHAR[type]);
2604
2605    switch(type)
2606    {
2607        case GB_DB:
2608            gbc = (GBCONTAINER *)gbd;
2609            size = gbc->d.size;
2610            printf("Size %i nheader %i hmemsize %i", gbc->d.size, gbc->d.nheader, gbc->d.headermemsize);
2611            printf(" father=(GBDATA*)0x%lx\n", (long)GB_FATHER(gbd));
2612            if (size < GB_info_deep){
2613                int index;
2614                struct gb_header_list_struct *header;
2615
2616                header = GB_DATA_LIST_HEADER(gbc->d);
2617                for (index = 0; index < gbc->d.nheader; index++) {
2618                    GBDATA *gb_sub = GB_HEADER_LIST_GBD(header[index]);
2619                    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);
2620                }
2621            }
2622            break;
2623        default:
2624            data = GB_read_as_string(gbd);
2625            if (data) {printf("%s",data); free(data);}
2626            printf(" father=(GBDATA*)0x%lx\n", (long)GB_FATHER(gbd));
2627    }
2628
2629
2630    GB_pop_transaction(gbd);
2631
2632    return 0;
2633}
2634
2635
2636int GB_info(GBDATA *gbd)
2637{
2638    return gb_info(gbd,0);
2639}
2640
2641long GB_number_of_subentries(GBDATA *gbd)
2642{
2643    long subentries = -1; 
2644
2645    if (GB_TYPE(gbd) == GB_DB) {
2646        GBCONTAINER *gbc = (GBCONTAINER*)gbd;
2647
2648        if (GB_is_server(gbd)) {
2649            subentries = gbc->d.size;
2650        }
2651        else { /* client really needs to count entries in header */
2652            int                           end    = gbc->d.nheader;
2653            struct gb_header_list_struct *header = GB_DATA_LIST_HEADER(gbc->d);
2654            int                           index;
2655
2656            subentries = 0;
2657            for (index = 0; index<end; index++) {
2658                if ((int)header[index].flags.changed < gb_deleted) subentries++;
2659            }
2660        }
2661    }
2662
2663    return subentries;
2664}
2665
2666
2667
2668
2669
Note: See TracBrowser for help on using the repository browser.