source: branches/port5/ARBDB/adquery.c

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