root/trunk/ARBDB/adindex.cxx

Revision 8607, 28.0 KB (checked in by westram, 5 weeks ago)

merge from e4fix [8135] [8136] [8137] [8138] [8139] [8140] [8141] [8142] [8143] [8144] [8222]
this revives the reverted patches [8129] [8130] [8131] [8132]

  • fixes
    • some free/delete mismatches
    • wrong definition of ORF objects (Level was no bit value)
    • amino consensus (failed for columns only containing 'C')
  • rename
    • AA_sequence_term -> orf_term
    • ED4_sequence_terminal_basic -> ED4_abstract_sequence_terminal
  • cleaned up hierarchy dumps
  • tweaked is_terminal()/to_terminal()
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1// =============================================================== //
2//                                                                 //
3//   File      : adindex.cxx                                       //
4//   Purpose   :                                                   //
5//                                                                 //
6//   Institute of Microbiology (Technical University Munich)       //
7//   http://www.arb-home.de/                                       //
8//                                                                 //
9// =============================================================== //
10
11#include "gb_undo.h"
12#include "gb_index.h"
13#include "gb_hashindex.h"
14#include "gb_ts.h"
15#include "gb_storage.h"
16
17#include <arb_strbuf.h>
18
19#include <cctype>
20
21#define GB_INDEX_FIND(gbf, ifs, quark)                                  \
22    for (ifs = GBCONTAINER_IFS(gbf);                                    \
23         ifs;                                                           \
24         ifs = GB_INDEX_FILES_NEXT(ifs))                                \
25    {                                                                   \
26        if (ifs->key == quark) break;                                   \
27    }
28
29// write field in index table
30char *gb_index_check_in(GBDATA *gbd)
31{
32    gb_index_files *ifs;
33    GBQUARK         quark;
34    unsigned long   index;
35    GB_CSTR         data;
36    GBCONTAINER    *gfather;
37
38    gfather = GB_GRANDPA(gbd);
39    if (!gfather)   return 0;
40
41    quark = GB_KEY_QUARK(gbd);
42    GB_INDEX_FIND(gfather, ifs, quark);
43    if (!ifs) return 0;     // This key is not indexed
44
45    if (GB_TYPE(gbd) != GB_STRING && GB_TYPE(gbd) != GB_LINK) return 0;
46
47    if (gbd->flags2.is_indexed)
48    {
49        GB_internal_error("Double checked in");
50        return 0;
51    }
52
53    data = GB_read_char_pntr(gbd);
54    GB_CALC_HASH_INDEX(data, index, ifs->hash_table_size, ifs->case_sens);
55    ifs->nr_of_elements++;
56    {
57        gb_if_entries *ifes;
58        GB_REL_IFES   *entries = GB_INDEX_FILES_ENTRIES(ifs);
59
60        ifes = (gb_if_entries *)gbm_get_mem(sizeof(gb_if_entries), GB_GBM_INDEX(gbd));
61
62        SET_GB_IF_ENTRIES_NEXT(ifes, GB_ENTRIES_ENTRY(entries, index));
63        SET_GB_IF_ENTRIES_GBD(ifes, gbd);
64        SET_GB_ENTRIES_ENTRY(entries, index, ifes);
65    }
66    gbd->flags2.tisa_index = 1;
67    gbd->flags2.is_indexed = 1;
68    return 0;
69}
70
71// remove entry from index table
72void gb_index_check_out(GBDATA *gbd) {
73    if (gbd->flags2.is_indexed) {
74        GB_ERROR        error   = 0;
75        GBCONTAINER    *gfather = GB_GRANDPA(gbd);
76        GBQUARK         quark   = GB_KEY_QUARK(gbd);
77        gb_index_files *ifs;
78
79        gbd->flags2.is_indexed = 0;
80        GB_INDEX_FIND(gfather, ifs, quark);
81
82        if (!ifs) error = "key is not indexed";
83        else {
84            error = GB_push_transaction(gbd);
85            if (!error) {
86                GB_CSTR data = GB_read_char_pntr(gbd);
87
88                if (!data) {
89                    error = GBS_global_string("can't read key value (%s)", GB_await_error());
90                }
91                else {
92                    unsigned long index;
93                    GB_CALC_HASH_INDEX(data, index, ifs->hash_table_size, ifs->case_sens);
94
95                    gb_if_entries *ifes2   = 0;
96                    GB_REL_IFES   *entries = GB_INDEX_FILES_ENTRIES(ifs);
97                    gb_if_entries *ifes;
98
99                    for (ifes = GB_ENTRIES_ENTRY(entries, index); ifes; ifes = GB_IF_ENTRIES_NEXT(ifes)) {
100                        if (gbd == GB_IF_ENTRIES_GBD(ifes)) {       // entry found
101                            if (ifes2) SET_GB_IF_ENTRIES_NEXT(ifes2, GB_IF_ENTRIES_NEXT(ifes));
102                            else SET_GB_ENTRIES_ENTRY(entries, index, GB_IF_ENTRIES_NEXT(ifes));
103
104                            ifs->nr_of_elements--;
105                            gbm_free_mem(ifes, sizeof(gb_if_entries), GB_GBM_INDEX(gbd));
106                            break;
107                        }
108                        ifes2 = ifes;
109                    }
110                }
111            }
112            error = GB_end_transaction(gbd, error);
113        }
114
115        if (error) {
116            error = GBS_global_string("gb_index_check_out failed for key '%s' (%s)\n", GB_KEY(gbd), error);
117            GB_internal_error(error);
118        }
119    }
120}
121
122GB_ERROR GB_create_index(GBDATA *gbd, const char *key, GB_CASE case_sens, long estimated_size) { // goes to header: __ATTR__USERESULT
123    /* Create an index for a database.
124     * Uses hash tables - collisions are avoided by using linked lists.
125     */
126    GB_ERROR error = 0;
127
128    if (GB_TYPE(gbd) != GB_DB) {
129        error = "GB_create_index used on non CONTAINER Type";
130    }
131    else if (GB_read_clients(gbd)<0) {
132        error = "No index tables in DB clients allowed";
133    }
134    else {
135        GBCONTAINER    *gbc       = (GBCONTAINER *)gbd;
136        GBQUARK         key_quark = GB_find_or_create_quark(gbd, key);
137        gb_index_files *ifs;
138
139        GB_INDEX_FIND(gbc, ifs, key_quark);
140
141        if (!ifs) { // if not already have index (e.g. if fast-loaded)
142            GBDATA *gbf;
143
144            ifs = (gb_index_files *)gbm_get_mem(sizeof(gb_index_files), GB_GBM_INDEX(gbc));
145            SET_GB_INDEX_FILES_NEXT(ifs, GBCONTAINER_IFS(gbc));
146            SET_GBCONTAINER_IFS(gbc, ifs);
147
148            ifs->key             = key_quark;
149            ifs->hash_table_size = gbs_get_a_prime(estimated_size);
150            ifs->nr_of_elements  = 0;
151            ifs->case_sens       = case_sens;
152
153            SET_GB_INDEX_FILES_ENTRIES(ifs, (gb_if_entries **)gbm_get_mem(sizeof(void *)*(int)ifs->hash_table_size, GB_GBM_INDEX(gbc)));
154
155            for (gbf = GB_find_sub_by_quark(gbd, -1, 0, 0);
156                 gbf;
157                 gbf = GB_find_sub_by_quark(gbd, -1, gbf, 0))
158            {
159                if (GB_TYPE(gbf) == GB_DB) {
160                    GBDATA *gb2;
161
162                    for (gb2 = GB_find_sub_by_quark(gbf, key_quark, 0, 0);
163                         gb2;
164                         gb2 = GB_find_sub_by_quark(gbf, key_quark, gb2, 0))
165                    {
166                        if (GB_TYPE(gb2) != GB_STRING && GB_TYPE(gb2) != GB_LINK) continue;
167                        gb_index_check_in(gb2);
168                    }
169                }
170            }
171        }
172    }
173    RETURN_ERROR(error);
174}
175
176void gb_destroy_indices(GBCONTAINER *gbc) {
177    gb_index_files *ifs = GBCONTAINER_IFS(gbc);
178
179    while (ifs) {
180        GB_REL_IFES *if_entries = GB_INDEX_FILES_ENTRIES(ifs);
181
182        for (int index = 0; index<ifs->hash_table_size; index++) {
183            gb_if_entries *ifes = GB_ENTRIES_ENTRY(if_entries, index);
184
185            while (ifes) {
186                gb_if_entries *ifes_next = GB_IF_ENTRIES_NEXT(ifes);
187
188                gbm_free_mem(ifes, sizeof(*ifes), GB_GBM_INDEX(gbc));
189                ifes = ifes_next;
190            }
191        }
192        gbm_free_mem(if_entries, sizeof(void *)*(int)ifs->hash_table_size, GB_GBM_INDEX(gbc));
193
194        gb_index_files *ifs_next = GB_INDEX_FILES_NEXT(ifs);
195        gbm_free_mem(ifs, sizeof(gb_index_files), GB_GBM_INDEX(gbc));
196        ifs = ifs_next;
197    }
198}
199
200#if defined(DEBUG)
201
202NOT4PERL void GB_dump_indices(GBDATA *gbd) {
203    // dump indices of container
204
205    char *db_path = strdup(GB_get_db_path(gbd));
206
207    if (GB_TYPE(gbd) != GB_DB) {
208        fprintf(stderr, "'%s' (%s) is no container.\n", db_path, GB_get_type_name(gbd));
209    }
210    else {
211        gb_index_files *ifs;
212        int             index_count = 0;
213        GBCONTAINER    *gbc         = (GBCONTAINER*)gbd;
214        GB_MAIN_TYPE   *Main        = GBCONTAINER_MAIN(gbc);
215
216        for (ifs = GBCONTAINER_IFS(gbc); ifs; ifs = GB_INDEX_FILES_NEXT(ifs)) {
217            index_count++;
218        }
219
220        if (index_count == 0) {
221            fprintf(stderr, "Container '%s' has no index.\n", db_path);
222        }
223        else {
224            int pass;
225
226            fprintf(stderr, "Indices for '%s':\n", db_path);
227            for (pass = 1; pass <= 2; pass++) {
228                if (pass == 2) {
229                    fprintf(stderr, "\nDetailed index contents:\n\n");
230                }
231                index_count = 0;
232                for (ifs = GBCONTAINER_IFS(gbc); ifs; ifs = GB_INDEX_FILES_NEXT(ifs)) {
233                    fprintf(stderr,
234                            "* Index %i for key=%s (%i), entries=%li, %s\n",
235                            index_count,
236                            Main->keys[ifs->key].key,
237                            ifs->key,
238                            ifs->nr_of_elements,
239                            ifs->case_sens == GB_MIND_CASE
240                            ? "Case sensitive"
241                            : (ifs->case_sens == GB_IGNORE_CASE
242                               ? "Case insensitive"
243                               : "<Error in case_sens>")
244                            );
245
246                    if (pass == 2) {
247                        gb_if_entries *ifes;
248                        int            index;
249
250                        fprintf(stderr, "\n");
251                        for (index = 0; index<ifs->hash_table_size; index++) {
252                            for (ifes = GB_ENTRIES_ENTRY(GB_INDEX_FILES_ENTRIES(ifs), index);
253                                 ifes;
254                                 ifes = GB_IF_ENTRIES_NEXT(ifes))
255                            {
256                                GBDATA     *igbd = GB_IF_ENTRIES_GBD(ifes);
257                                const char *data = GB_read_char_pntr(igbd);
258
259                                fprintf(stderr, "  - '%s' (@idx=%i)\n", data, index);
260                            }
261                        }
262                        fprintf(stderr, "\n");
263                    }
264                    index_count++;
265                }
266            }
267        }
268    }
269
270    free(db_path);
271}
272
273#endif // DEBUG
274
275
276// find an entry in an hash table
277GBDATA *gb_index_find(GBCONTAINER *gbf, gb_index_files *ifs, GBQUARK quark, const char *val, GB_CASE case_sens, int after_index) {
278    unsigned long  index;
279    GB_CSTR        data;
280    gb_if_entries *ifes;
281    GBDATA        *result = 0;
282    long           min_index;
283
284    if (!ifs) {
285        GB_INDEX_FIND(gbf, ifs, quark);
286        if (!ifs) {
287            GB_internal_error("gb_index_find called, but no index table found");
288            return 0;
289        }
290    }
291
292    if (ifs->case_sens != case_sens) {
293        GB_internal_error("case mismatch between index and search");
294        return 0;
295    }
296
297    GB_CALC_HASH_INDEX(val, index, ifs->hash_table_size, ifs->case_sens);
298    min_index = gbf->d.nheader;
299
300    for (ifes = GB_ENTRIES_ENTRY(GB_INDEX_FILES_ENTRIES(ifs), index);
301            ifes;
302            ifes = GB_IF_ENTRIES_NEXT(ifes))
303    {
304        GBDATA *igbd = GB_IF_ENTRIES_GBD(ifes);
305        GBCONTAINER *ifather = GB_FATHER(igbd);
306
307        if (ifather->index < after_index) continue;
308        if (ifather->index >= min_index) continue;
309        data = GB_read_char_pntr(igbd);
310        if (GBS_string_matches(data, val, case_sens)) { // entry found
311            result    = igbd;
312            min_index = ifather->index;
313        }
314    }
315    return result;
316}
317
318
319/* UNDO functions
320 *
321 * There are three undo stacks:
322 *
323 * GB_UNDO_NONE    no undo
324 * GB_UNDO_UNDO    normal undo stack
325 * GB_UNDO_REDO    redo stack
326 */
327
328static char *gb_set_undo_type(GBDATA *gb_main, GB_UNDO_TYPE type) {
329    GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
330    Main->undo_type = type;
331    return 0;
332}
333
334static void g_b_add_size_to_undo_entry(g_b_undo_entry *ue, long size) {
335    ue->sizeof_this                 += size;        // undo entry
336    ue->father->sizeof_this         += size;        // one undo
337    ue->father->father->sizeof_this += size;        // all undos
338}
339
340static g_b_undo_entry *new_g_b_undo_entry(g_b_undo_list *u) {
341    g_b_undo_entry *ue = (g_b_undo_entry *)gbm_get_mem(sizeof(g_b_undo_entry), GBM_UNDO);
342
343    ue->next   = u->entries;
344    ue->father = u;
345    u->entries = ue;
346
347    g_b_add_size_to_undo_entry(ue, sizeof(g_b_undo_entry));
348
349    return ue;
350}
351
352
353
354void gb_init_undo_stack(GB_MAIN_TYPE *Main) {
355    Main->undo = (g_b_undo_mgr *)GB_calloc(sizeof(g_b_undo_mgr), 1);
356    Main->undo->max_size_of_all_undos = GB_MAX_UNDO_SIZE;
357    Main->undo->u = (g_b_undo_header *) GB_calloc(sizeof(g_b_undo_header), 1);
358    Main->undo->r = (g_b_undo_header *) GB_calloc(sizeof(g_b_undo_header), 1);
359}
360
361static void delete_g_b_undo_entry(g_b_undo_entry *entry) {
362    switch (entry->type) {
363        case GB_UNDO_ENTRY_TYPE_MODIFY:
364        case GB_UNDO_ENTRY_TYPE_MODIFY_ARRAY:
365            {
366                if (entry->d.ts) {
367                    gb_del_ref_gb_transaction_save(entry->d.ts);
368                }
369            }
370        default:
371            break;
372    }
373    gbm_free_mem(entry, sizeof(g_b_undo_entry), GBM_UNDO);
374}
375
376static void delete_g_b_undo_list(g_b_undo_list *u) {
377    g_b_undo_entry *a, *next;
378    for (a = u->entries; a; a = next) {
379        next = a->next;
380        delete_g_b_undo_entry(a);
381    }
382    free(u);
383}
384
385static void delete_g_b_undo_header(g_b_undo_header *uh) {
386    g_b_undo_list *a, *next=0;
387    for (a = uh->stack; a; a = next) {
388        next = a->next;
389        delete_g_b_undo_list(a);
390    }
391    free(uh);
392}
393
394static char *g_b_check_undo_size2(g_b_undo_header *uhs, long size, long max_cnt) {
395    long           csize = 0;
396    long           ccnt  = 0;
397    g_b_undo_list *us;
398
399    for (us = uhs->stack; us && us->next;  us = us->next) {
400        csize += us->sizeof_this;
401        ccnt ++;
402        if (((csize + us->next->sizeof_this) > size) ||
403             (ccnt >= max_cnt)) {  // delete the rest
404            g_b_undo_list *a, *next=0;
405
406            for (a = us->next; a; a = next) {
407                next = a->next;
408                delete_g_b_undo_list(a);
409            }
410            us->next = 0;
411            uhs->sizeof_this = csize;
412            break;
413        }
414    }
415    return 0;
416}
417
418static char *g_b_check_undo_size(GB_MAIN_TYPE *Main) {
419    char *error = 0;
420    long maxsize = Main->undo->max_size_of_all_undos;
421    error = g_b_check_undo_size2(Main->undo->u, maxsize/2, GB_MAX_UNDO_CNT);
422    if (error) return error;
423    error = g_b_check_undo_size2(Main->undo->r, maxsize/2, GB_MAX_REDO_CNT);
424    if (error) return error;
425    return 0;
426}
427
428
429void gb_free_undo_stack(GB_MAIN_TYPE *Main) {
430    delete_g_b_undo_header(Main->undo->u);
431    delete_g_b_undo_header(Main->undo->r);
432    free(Main->undo);
433}
434
435// -------------------------
436//      real undo (redo)
437
438static GB_ERROR undo_entry(g_b_undo_entry *ue) {
439    GB_ERROR error = 0;
440    switch (ue->type) {
441        case GB_UNDO_ENTRY_TYPE_CREATED:
442            error = GB_delete(ue->source);
443            break;
444        case GB_UNDO_ENTRY_TYPE_DELETED:
445            {
446                GBDATA *gbd = ue->d.gs.gbd;
447                int type = GB_TYPE(gbd);
448                if (type == GB_DB) {
449                    gbd = (GBDATA *)gb_make_pre_defined_container((GBCONTAINER *)ue->source, (GBCONTAINER *)gbd, -1, ue->d.gs.key);
450                }
451                else {
452                    gbd = gb_make_pre_defined_entry((GBCONTAINER *)ue->source, gbd, -1, ue->d.gs.key);
453                }
454                GB_ARRAY_FLAGS(gbd).flags = ue->flag;
455                gb_touch_header(GB_FATHER(gbd));
456                gb_touch_entry((GBDATA *)gbd, GB_CREATED);
457            }
458            break;
459        case GB_UNDO_ENTRY_TYPE_MODIFY_ARRAY:
460        case GB_UNDO_ENTRY_TYPE_MODIFY:
461            {
462                GBDATA *gbd = ue->source;
463                int type  = GB_TYPE(gbd);
464                if (type == GB_DB) {
465
466                }
467                else {
468                    gb_save_extern_data_in_ts(gbd); // check out and free string
469
470                    if (ue->d.ts) { // nothing to undo (e.g. if undoing GB_touch)
471                        gbd->flags              = ue->d.ts->flags;
472                        gbd->flags2.extern_data = ue->d.ts->flags2.extern_data;
473
474                        memcpy(&gbd->info, &ue->d.ts->info, sizeof(gbd->info)); // restore old information
475                        if (type >= GB_BITS) {
476                            if (gbd->flags2.extern_data) {
477                                SET_GB_EXTERN_DATA_DATA(gbd->info.ex, ue->d.ts->info.ex.data); // set relative pointers correctly
478                            }
479
480                            gb_del_ref_and_extern_gb_transaction_save(ue->d.ts);
481                            ue->d.ts = 0;
482
483                            GB_INDEX_CHECK_IN(gbd);
484                        }
485                    }
486                }
487                {
488                    gb_header_flags *pflags = &GB_ARRAY_FLAGS(gbd);
489                    if (pflags->flags != (unsigned)ue->flag) {
490                        GBCONTAINER *gb_father = GB_FATHER(gbd);
491                        gbd->flags.saved_flags = pflags->flags;
492                        pflags->flags = ue->flag;
493                        if (GB_FATHER(gb_father)) {
494                            gb_touch_header(gb_father); // don't touch father of main
495                        }
496                    }
497                }
498                gb_touch_entry(gbd, GB_NORMAL_CHANGE);
499            }
500            break;
501        default:
502            GB_internal_error("Undo stack corrupt:!!!");
503            error = GB_export_error("shit 34345");
504    }
505
506    return error;
507}
508
509
510
511static GB_ERROR g_b_undo(GBDATA *gb_main, g_b_undo_header *uh) { // goes to header: __ATTR__USERESULT
512    GB_ERROR error = NULL;
513
514    if (!uh->stack) {
515        error = "Sorry no more undos/redos available";
516    }
517    else {
518        g_b_undo_list  *u = uh->stack;
519        g_b_undo_entry *ue, *next;
520
521        error = GB_begin_transaction(gb_main);
522
523        for (ue=u->entries; ue && !error; ue = next) {
524            next = ue->next;
525            error = undo_entry(ue);
526            delete_g_b_undo_entry(ue);
527            u->entries = next;
528        }
529        uh->sizeof_this -= u->sizeof_this;          // remove undo from list
530        uh->stack        = u->next;
531
532        delete_g_b_undo_list(u);
533        error = GB_end_transaction(gb_main, error);
534    }
535    return error;
536}
537
538static GB_CSTR g_b_read_undo_key_pntr(GB_MAIN_TYPE *Main, g_b_undo_entry *ue) {
539    return Main->keys[ue->d.gs.key].key;
540}
541
542static char *g_b_undo_info(GB_MAIN_TYPE *Main, g_b_undo_header *uh) {
543    GBS_strstruct  *res = GBS_stropen(1024);
544    g_b_undo_list  *u;
545    g_b_undo_entry *ue;
546
547    u = uh->stack;
548    if (!u) return strdup("No more undos available");
549    for (ue=u->entries; ue; ue = ue->next) {
550        switch (ue->type) {
551            case GB_UNDO_ENTRY_TYPE_CREATED:
552                GBS_strcat(res, "Delete new entry: ");
553                GBS_strcat(res, gb_read_key_pntr(ue->source));
554                break;
555            case GB_UNDO_ENTRY_TYPE_DELETED:
556                GBS_strcat(res, "Rebuild deleted entry: ");
557                GBS_strcat(res, g_b_read_undo_key_pntr(Main, ue));
558                break;
559            case GB_UNDO_ENTRY_TYPE_MODIFY_ARRAY:
560            case GB_UNDO_ENTRY_TYPE_MODIFY:
561                GBS_strcat(res, "Undo modified entry: ");
562                GBS_strcat(res, gb_read_key_pntr(ue->source));
563                break;
564            default:
565                break;
566        }
567        GBS_chrcat(res, '\n');
568    }
569    return GBS_strclose(res);
570}
571
572static char *gb_free_all_undos(GBDATA *gb_main) {
573    // Remove all existing undos/redos
574    GB_MAIN_TYPE  *Main = GB_MAIN(gb_main);
575    g_b_undo_list *a, *next;
576   
577    for (a = Main->undo->r->stack; a; a = next) {
578        next = a->next;
579        delete_g_b_undo_list(a);
580    }
581    Main->undo->r->stack = 0;
582    Main->undo->r->sizeof_this = 0;
583
584    for (a = Main->undo->u->stack; a; a = next) {
585        next = a->next;
586        delete_g_b_undo_list(a);
587    }
588    Main->undo->u->stack = 0;
589    Main->undo->u->sizeof_this = 0;
590    return 0;
591}
592
593
594char *gb_set_undo_sync(GBDATA *gb_main) {
595    // start a new undoable transaction
596    GB_MAIN_TYPE    *Main  = GB_MAIN(gb_main);
597    char            *error = g_b_check_undo_size(Main);
598    g_b_undo_header *uhs;
599
600    if (error) return error;
601    switch (Main->requested_undo_type) {    // init the target undo stack
602        case GB_UNDO_UNDO:      // that will undo but delete all redos
603            uhs         = Main->undo->u;
604            break;
605        case GB_UNDO_UNDO_REDO: uhs = Main->undo->u; break;
606        case GB_UNDO_REDO:      uhs = Main->undo->r; break;
607        case GB_UNDO_KILL:      gb_free_all_undos(gb_main);
608        default:            uhs = 0;
609    }
610    if (uhs)
611    {
612        g_b_undo_list *u = (g_b_undo_list *) GB_calloc(sizeof(g_b_undo_list),  1);
613        u->next = uhs->stack;
614        u->father = uhs;
615        uhs->stack = u;
616        Main->undo->valid_u = u;
617    }
618
619    return gb_set_undo_type(gb_main, Main->requested_undo_type);
620}
621
622char *gb_disable_undo(GBDATA *gb_main) {
623    // called to finish an undoable section, called at end of gb_commit_transaction
624    GB_MAIN_TYPE  *Main = GB_MAIN(gb_main);
625    g_b_undo_list *u    = Main->undo->valid_u;
626
627    if (!u) return 0;
628    if (!u->entries) {      // nothing to undo, just a read transaction
629        u->father->stack = u->next;
630        delete_g_b_undo_list(u);
631    }
632    else {
633        if (Main->requested_undo_type == GB_UNDO_UNDO) {    // remove all redos
634            g_b_undo_list *a, *next;
635
636            for (a = Main->undo->r->stack; a; a = next) {
637                next = a->next;
638                delete_g_b_undo_list(a);
639            }
640            Main->undo->r->stack = 0;
641            Main->undo->r->sizeof_this = 0;
642        }
643    }
644    Main->undo->valid_u = 0;
645    return gb_set_undo_type(gb_main, GB_UNDO_NONE);
646}
647
648void gb_check_in_undo_create(GB_MAIN_TYPE *Main, GBDATA *gbd) {
649    g_b_undo_entry *ue;
650    if (!Main->undo->valid_u) return;
651    ue = new_g_b_undo_entry(Main->undo->valid_u);
652    ue->type = GB_UNDO_ENTRY_TYPE_CREATED;
653    ue->source = gbd;
654    ue->gbm_index = GB_GBM_INDEX(gbd);
655    ue->flag = 0;
656}
657
658void gb_check_in_undo_modify(GB_MAIN_TYPE *Main, GBDATA *gbd) {
659    long                 type = GB_TYPE(gbd);
660    g_b_undo_entry      *ue;
661    gb_transaction_save *old;
662
663    if (!Main->undo->valid_u) {
664        GB_FREE_TRANSACTION_SAVE(gbd);
665        return;
666    }
667
668    old = GB_GET_EXT_OLD_DATA(gbd);
669    ue = new_g_b_undo_entry(Main->undo->valid_u);
670    ue->source = gbd;
671    ue->gbm_index = GB_GBM_INDEX(gbd);
672    ue->type = GB_UNDO_ENTRY_TYPE_MODIFY;
673    ue->flag =      gbd->flags.saved_flags;
674
675    if (type != GB_DB) {
676        ue->d.ts = old;
677        if (old) {
678            gb_add_ref_gb_transaction_save(old);
679            if (type >= GB_BITS && old->flags2.extern_data && old->info.ex.data) {
680                ue->type = GB_UNDO_ENTRY_TYPE_MODIFY_ARRAY;
681                // move external array from ts to undo entry struct
682                g_b_add_size_to_undo_entry(ue, old->info.ex.memsize);
683            }
684        }
685    }
686}
687
688#if defined(WARN_TODO)
689#warning change param for gb_check_in_undo_delete to GBDATA **
690#endif
691
692void gb_check_in_undo_delete(GB_MAIN_TYPE *Main, GBDATA *gbd, int deep) {
693    long            type = GB_TYPE(gbd);
694    g_b_undo_entry *ue;
695
696    if (!Main->undo->valid_u) {
697        gb_delete_entry(&gbd);
698        return;
699    }
700
701    if (type == GB_DB) {
702        int             index;
703        GBDATA         *gbd2;
704        GBCONTAINER    *gbc = ((GBCONTAINER *) gbd);
705
706        for (index = 0; (index < gbc->d.nheader); index++) {
707            if ((gbd2 = GBCONTAINER_ELEM(gbc, index))) {
708                gb_check_in_undo_delete(Main, gbd2, deep+1);
709            }
710        };
711    }
712    else {
713        GB_INDEX_CHECK_OUT(gbd);
714        gbd->flags2.tisa_index = 0; // never check in again
715    }
716    gb_abort_entry(gbd);            // get old version
717
718    ue = new_g_b_undo_entry(Main->undo->valid_u);
719
720    ue->type      = GB_UNDO_ENTRY_TYPE_DELETED;
721    ue->source    = (GBDATA *)GB_FATHER(gbd);
722    ue->gbm_index = GB_GBM_INDEX(gbd);
723    ue->flag      = GB_ARRAY_FLAGS(gbd).flags;
724
725    ue->d.gs.gbd = gbd;
726    ue->d.gs.key = GB_KEY_QUARK(gbd);
727
728    gb_pre_delete_entry(gbd);       // get the core of the entry
729
730    if (type == GB_DB) {
731        g_b_add_size_to_undo_entry(ue, sizeof(GBCONTAINER));
732    }
733    else {
734        if (type >= GB_BITS && gbd->flags2.extern_data) {
735            /* we have copied the data structures, now
736               mark the old as deleted !!! */
737            g_b_add_size_to_undo_entry(ue, GB_GETMEMSIZE(gbd));
738        }
739        g_b_add_size_to_undo_entry(ue, sizeof(GBDATA));
740    }
741}
742
743// ----------------------------------------
744//      UNDO functions exported to USER
745
746GB_ERROR GB_request_undo_type(GBDATA *gb_main, GB_UNDO_TYPE type) { // goes to header: __ATTR__USERESULT_TODO
747    /*! Define how to undo DB changes.
748     *
749     * This function should be called just before opening a transaction,
750     * otherwise its effect will be delayed.
751     *
752     * Possible types are:
753     *      GB_UNDO_UNDO        enable undo
754     *      GB_UNDO_NONE        disable undo
755     *      GB_UNDO_KILL        disable undo and remove old undos !!
756     *
757     * Note: if GB_request_undo_type returns an error, local undo type remains unchanged
758     */
759
760    GB_MAIN_TYPE *Main  = GB_MAIN(gb_main);
761    GB_ERROR      error = NULL;
762
763    if (!Main->local_mode) {
764        enum gb_undo_commands cmd = (type == GB_UNDO_NONE || type == GB_UNDO_KILL)
765            ? _GBCMC_UNDOCOM_REQUEST_NOUNDO
766            : _GBCMC_UNDOCOM_REQUEST_UNDO;
767        error = gbcmc_send_undo_commands(gb_main, cmd);
768    }
769    if (!error) Main->requested_undo_type = type;
770
771    return error;
772}
773
774GB_UNDO_TYPE GB_get_requested_undo_type(GBDATA *gb_main) {
775    GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
776    return Main->requested_undo_type;
777}
778
779
780GB_ERROR GB_undo(GBDATA *gb_main, GB_UNDO_TYPE type) { // goes to header: __ATTR__USERESULT
781    // undo/redo the last transaction
782
783    GB_MAIN_TYPE *Main  = GB_MAIN(gb_main);
784    GB_ERROR      error = 0;
785
786    if (!Main->local_mode) {
787        switch (type) {
788            case GB_UNDO_UNDO:
789                error = gbcmc_send_undo_commands(gb_main, _GBCMC_UNDOCOM_UNDO);
790                break;
791
792            case GB_UNDO_REDO:
793                error = gbcmc_send_undo_commands(gb_main, _GBCMC_UNDOCOM_REDO);
794                break;
795
796            default:
797                GB_internal_error("unknown undo type in GB_undo");
798                error = "Internal UNDO error";
799                break;
800        }
801    }
802    else {
803        GB_UNDO_TYPE old_type = GB_get_requested_undo_type(gb_main);
804        switch (type) {
805            case GB_UNDO_UNDO:
806                error = GB_request_undo_type(gb_main, GB_UNDO_REDO);
807                if (!error) {
808                    error = g_b_undo(gb_main, Main->undo->u);
809                    ASSERT_NO_ERROR(GB_request_undo_type(gb_main, old_type));
810                }
811                break;
812
813            case GB_UNDO_REDO:
814                error = GB_request_undo_type(gb_main, GB_UNDO_UNDO_REDO);
815                if (!error) {
816                    error = g_b_undo(gb_main, Main->undo->r);
817                    ASSERT_NO_ERROR(GB_request_undo_type(gb_main, old_type));
818                }
819                break;
820
821            default:
822                error = "GB_undo: unknown undo type specified";
823                break;
824        }
825    }
826
827    return error;
828}
829
830
831char *GB_undo_info(GBDATA *gb_main, GB_UNDO_TYPE type) {
832    // get some information about the next undo
833
834    GB_MAIN_TYPE *Main = GB_MAIN(gb_main);
835    if (!Main->local_mode) {
836        switch (type) {
837            case GB_UNDO_UNDO:
838                return gbcmc_send_undo_info_commands(gb_main, _GBCMC_UNDOCOM_INFO_UNDO);
839            case GB_UNDO_REDO:
840                return gbcmc_send_undo_info_commands(gb_main, _GBCMC_UNDOCOM_INFO_REDO);
841            default:
842                GB_internal_error("unknown undo type in GB_undo");
843                GB_export_error("Internal UNDO error");
844                return 0;
845        }
846    }
847    switch (type) {
848        case GB_UNDO_UNDO:
849            return g_b_undo_info(Main, Main->undo->u);
850        case GB_UNDO_REDO:
851            return g_b_undo_info(Main, Main->undo->r);
852        default:
853            GB_export_error("GB_undo_info: unknown undo type specified");
854            return 0;
855    }
856}
857
858GB_ERROR GB_set_undo_mem(GBDATA *gbd, long memsize) {
859    // set the maximum memory used for undoing
860
861    GB_MAIN_TYPE *Main = GB_MAIN(gbd);
862    if (memsize < _GBCMC_UNDOCOM_SET_MEM) {
863        return GB_export_errorf("Not enough UNDO memory specified: should be more than %i",
864                                _GBCMC_UNDOCOM_SET_MEM);
865    }
866    Main->undo->max_size_of_all_undos = memsize;
867    if (!Main->local_mode) {
868        return gbcmc_send_undo_commands(gbd, (enum gb_undo_commands)memsize);
869    }
870    g_b_check_undo_size(Main);
871    return 0;
872}
Note: See TracBrowser for help on using the browser.