source: tags/svn.1.5.4/EDIT4/ED4_block.cxx

Last change on this file was 8309, checked in by westram, 14 years ago
  • moved much code into static scope

(partly reverted by [8310])

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 29.1 KB
Line 
1#include <arbdbt.h>
2#include <aw_awars.hxx>
3#include <aw_msg.hxx>
4#include <aw_root.hxx>
5#include <fast_aligner.hxx>
6
7#include "ed4_awars.hxx"
8#include "ed4_class.hxx"
9#include "ed4_tools.hxx"
10#include "ed4_block.hxx"
11#include "ed4_edit_string.hxx"
12
13#include <climits>
14#include <cctype>
15
16// --------------------------------------------------------------------------------
17
18static ED4_blocktype blocktype = ED4_BT_NOBLOCK;
19
20// linerange for COLUMNBLOCK is stored in EDIT4 marks,
21// columnrange for COLUMNBLOCK is stored here:
22
23static int range_col1, range_col2;
24static int columnBlockUsed = 0;
25
26// --------------------------------------------------------------------------------
27
28static void col_block_refresh_on_seq_term(ED4_sequence_terminal *seq_term) {
29    seq_term->set_refresh(1);
30    seq_term->parent->refresh_requested_by_child();
31
32    ED4_columnStat_terminal *colStatTerm = seq_term->corresponding_columnStat_terminal();
33    if (colStatTerm) {
34        const char *probe_match_pattern = colStatTerm->build_probe_match_string(range_col1, range_col2);
35        int len = strlen(probe_match_pattern);
36
37        if (len>=4) {
38            colStatTerm->set_refresh(1);
39            colStatTerm->parent->refresh_requested_by_child();
40
41            // automatically set probe-match awars to appropriate values:
42
43            ED4_ROOT->aw_root->awar(ED4_AWAR_PROBE_SEARCH_MAX_MISMATCHES)->write_int(0); // no mismatches
44            ED4_ROOT->aw_root->awar(ED4_AWAR_PROBE_SEARCH_AUTO_JUMP)->write_int(0); // disable auto jump
45            ED4_ROOT->aw_root->awar(AWAR_MAX_MISMATCHES)->write_int(0); // probe search w/o mismatches
46            ED4_ROOT->aw_root->awar(AWAR_ITARGET_STRING)->write_string(probe_match_pattern); // set probe search string
47        }
48    }
49}
50// --------------------------------------------------------------------------------
51
52// if block_operation() returns NULL => no changes will be made to database
53// otherwise the changed sequence(part) will be written to the database
54
55static GB_ERROR perform_block_operation_on_whole_sequence(ED4_blockoperation block_operation, ED4_sequence_terminal *term, int repeat) {
56    GBDATA *gbd = term->get_species_pointer();
57    GB_ERROR error = 0;
58
59    if (gbd) {
60        char *seq = GB_read_string(gbd);
61        int len = GB_read_string_count(gbd);
62
63        int new_len;
64        char *new_seq = block_operation(seq, len, repeat, &new_len, &error);
65
66        if (new_seq) {
67            if (new_len<len) {
68                memcpy(seq, new_seq, new_len);
69                char gap = ADPP_IS_ALIGN_CHARACTER(seq[len-1]) ? seq[len-1] : '.';
70                int l;
71                for (l=new_len; l<len; l++) {
72                    seq[l] = gap;
73                }
74                seq[l] = 0;
75            }
76            else if (new_len>len) {
77                for (int l=new_len-1; l>=len; l--) {
78                    if (!ADPP_IS_ALIGN_CHARACTER(new_seq[l])) {
79                        error = "Result of block-operation to large (not enough gaps at end of sequence data)";
80                        break;
81                    }
82                }
83
84                if (!error) { // there are enough gaps at end of sequence
85                    memcpy(seq, new_seq, len);
86                }
87            }
88            else {
89                memcpy(seq, new_seq, len);
90            }
91            delete new_seq;
92
93            if (!error) {
94                error = GB_write_string(gbd, seq);
95                if (!error) {
96                    term->set_refresh();
97                    term->parent->refresh_requested_by_child();
98                }
99            }
100        }
101
102        delete seq;
103    }
104
105    return error;
106}
107
108// uses range_col1 till range_col2 as range
109static GB_ERROR perform_block_operation_on_part_of_sequence(ED4_blockoperation block_operation, ED4_sequence_terminal *term, int repeat) {
110    GBDATA *gbd = term->get_species_pointer();
111    GB_ERROR error = 0;
112
113    if (gbd) {
114        char *seq = GB_read_string(gbd);
115        int len = GB_read_string_count(gbd);
116
117        if (range_col1>=len || range_col2>=len) {
118            error = "Column-range exceeds sequence length";
119        }
120        else {
121            int len_part = range_col2-range_col1+1;
122            char *seq_part = seq+range_col1;
123            int new_len;
124            char *new_seq_part = block_operation(seq_part, len_part, repeat, &new_len, &error);
125
126            if (new_seq_part) {
127                if (new_len<len_part) {
128                    memcpy(seq_part, new_seq_part, new_len);
129                    char gap = '-';
130                    if (seq_part[len_part-1] == '.' || seq_part[len_part] == '.') gap = '.';
131
132                    for (int l=new_len; l<len_part; l++) {
133                        seq_part[l] = gap;
134                    }
135                }
136                else if (new_len>len_part) {
137                    for (int l=new_len-1; l>=len_part; l--) {
138                        if (!ADPP_IS_ALIGN_CHARACTER(new_seq_part[l])) {
139                            error = "Result of block-operation to large (not enough gaps at end of marked columnblock)";
140                            break;
141                        }
142                    }
143
144                    if (!error) { // there are enough gaps at end of sequence
145                        memcpy(seq_part, new_seq_part, len_part);
146                    }
147                }
148                else {
149                    memcpy(seq_part, new_seq_part, len_part);
150                }
151                delete new_seq_part;
152
153                if (!error) {
154                    error = GB_write_as_string(gbd, seq);
155                    if (!error) {
156                        term->set_refresh();
157                        term->parent->refresh_requested_by_child();
158                    }
159                }
160            }
161        }
162
163        delete seq;
164    }
165
166    return error;
167}
168
169
170
171static void ED4_with_whole_block(ED4_blockoperation block_operation, int repeat) {
172    GB_ERROR    error    = GB_begin_transaction(GLOBAL_gb_main);
173    ED4_cursor *cursor   = &ED4_ROOT->get_ed4w()->cursor;
174    int         base_pos = (cursor && cursor->owner_of_cursor != 0) ? cursor->get_base_position() : -1;
175
176    switch (blocktype) {
177        case ED4_BT_NOBLOCK: {
178            aw_message("No block marked -- use right mouse button");
179            break;
180        }
181        case ED4_BT_LINEBLOCK:
182        case ED4_BT_MODIFIED_COLUMNBLOCK:
183        case ED4_BT_COLUMNBLOCK: {
184            ED4_list_elem *listElem = ED4_ROOT->selected_objects.first();
185            while (listElem && !error) {
186                ED4_selection_entry   *selectionEntry = (ED4_selection_entry*)listElem->elem();
187                ED4_sequence_terminal *seqTerm        = selectionEntry->object->get_parent(ED4_L_SPECIES)->search_spec_child_rek(ED4_L_SEQUENCE_STRING)->to_sequence_terminal();
188
189                error = blocktype == ED4_BT_LINEBLOCK
190                    ? perform_block_operation_on_whole_sequence(block_operation, seqTerm, repeat)
191                    : perform_block_operation_on_part_of_sequence(block_operation, seqTerm, repeat);
192
193                listElem = listElem->next();
194            }
195            break;
196        }
197        default: {
198            error = "Illegal blocktype";
199            break;
200        }
201    }
202
203    if (error) error = GBS_global_string("[In block operation] %s", error);
204    GB_end_transaction_show_error(GLOBAL_gb_main, error, aw_message);
205
206    if (!error && base_pos != -1) {
207        cursor->jump_base_pos(ED4_ROOT->get_aww(), base_pos, ED4_JUMP_KEEP_VISIBLE); // restore cursor at same base
208    }
209}
210
211int ED4_get_selected_range(ED4_terminal *term, int *first_column, int *last_column) {
212    if (blocktype==ED4_BT_NOBLOCK) return 0;
213
214    if (blocktype==ED4_BT_COLUMNBLOCK || blocktype==ED4_BT_MODIFIED_COLUMNBLOCK) {
215        *first_column = range_col1;
216        *last_column = range_col2;
217    }
218    else {
219        e4_assert(blocktype==ED4_BT_LINEBLOCK);
220        *first_column = 0;
221        *last_column = -1;
222    }
223
224    ED4_species_name_terminal *name_term = term->to_sequence_terminal()->corresponding_species_name_terminal();
225    return name_term->flag.selected;
226}
227
228ED4_blocktype ED4_getBlocktype() {
229    return blocktype;
230}
231void ED4_setBlocktype(ED4_blocktype bt) {
232    if (blocktype!=bt) {
233        blocktype = bt;
234
235        ED4_list_elem *listElem = ED4_ROOT->selected_objects.first();
236        while (listElem) {
237            ED4_selection_entry *selected = (ED4_selection_entry*)listElem->elem();
238            ED4_species_name_terminal *name_term = selected->object->to_species_name_terminal();
239            ED4_sequence_terminal *seq_term = name_term->corresponding_sequence_terminal();
240
241            name_term->set_refresh(1);
242            name_term->parent->refresh_requested_by_child();
243            if (seq_term) col_block_refresh_on_seq_term(seq_term);
244
245            listElem = listElem->next();
246        }
247
248        if (blocktype==ED4_BT_COLUMNBLOCK || blocktype==ED4_BT_MODIFIED_COLUMNBLOCK) {
249            columnBlockUsed = 1;
250        }
251    }
252}
253
254void ED4_toggle_block_type() {
255    switch (blocktype) {
256        case ED4_BT_NOBLOCK: {
257            aw_message("No block selected.");
258            break;
259        }
260        case ED4_BT_LINEBLOCK: {
261            if (columnBlockUsed) {
262                ED4_setBlocktype(ED4_BT_MODIFIED_COLUMNBLOCK);
263            }
264            else {
265                aw_message("No columnblock marked so far  - I can't guess the column range");
266            }
267            break;
268        }
269        case ED4_BT_MODIFIED_COLUMNBLOCK:
270        case ED4_BT_COLUMNBLOCK: {
271            ED4_setBlocktype(ED4_BT_LINEBLOCK);
272            break;
273        }
274        default: {
275            e4_assert(0);
276            break;
277        }
278    }
279}
280
281void ED4_correctBlocktypeAfterSelection() { // this has to be called every time the selection has changed
282
283    if (ED4_ROOT->selected_objects.first()==0) { // no objects are selected
284        ED4_setBlocktype(ED4_BT_NOBLOCK);
285    }
286    else {
287        switch (ED4_getBlocktype()) {
288            case ED4_BT_NOBLOCK: {
289                ED4_setBlocktype(ED4_BT_LINEBLOCK);
290                break;
291            }
292            case ED4_BT_COLUMNBLOCK: {
293                ED4_setBlocktype(ED4_BT_MODIFIED_COLUMNBLOCK);
294                break;
295            }
296            case ED4_BT_LINEBLOCK:
297            case ED4_BT_MODIFIED_COLUMNBLOCK: {
298                break;
299            }
300            default: {
301                e4_assert(0);
302                break;
303            }
304        }
305    }
306}
307
308static void select_and_update(ED4_sequence_terminal *term1, ED4_sequence_terminal *term2, ED4_index pos1, ED4_index pos2, int initial_call) {
309    static ED4_sequence_terminal *last_term1, *last_term2;
310    static ED4_index last_pos1, last_pos2;
311
312    if (pos1>pos2) {
313        range_col1 = pos2;
314        range_col2 = pos1;
315    }
316    else {
317        range_col1 = pos1;
318        range_col2 = pos2;
319    }
320
321    if (blocktype==ED4_BT_MODIFIED_COLUMNBLOCK) {
322        ED4_list_elem *listElem = ED4_ROOT->selected_objects.first();
323        while (listElem) {
324            ED4_selection_entry *selectionEntry = (ED4_selection_entry*)listElem->elem();
325            ED4_species_name_terminal *name_term = selectionEntry->object->to_species_name_terminal();
326            ED4_sequence_terminal *seq_term = name_term->corresponding_sequence_terminal();
327
328            if (seq_term) col_block_refresh_on_seq_term(seq_term);
329
330            listElem = listElem->next();
331        }
332    }
333    else {
334        { // ensure term1 is the upper terminal
335            AW_pos dummy, y1, y2;
336
337            term1->calc_world_coords(&dummy, &y1);
338            term2->calc_world_coords(&dummy, &y2);
339
340            if (y1>y2) {
341                ED4_sequence_terminal *t = term1; term1 = term2; term2 = t;
342                AW_pos y = y1; y1 = y2; y2 = y;
343            }
344        }
345
346        int do_above = 1; // we have to update terminals between last_term1 and term1
347        int do_below = 1; // we have to update terminals between term2 and last_term2
348
349        ED4_terminal *term          = term1;
350        int           xRangeChanged = last_pos1!=range_col1 || last_pos2!=range_col2;
351
352        while (term) {
353            if (term->is_sequence_terminal()) {
354                ED4_sequence_terminal *seq_term = term->to_sequence_terminal();
355
356                if (seq_term==last_term1) {
357                    do_above = 0;
358                }
359                if (seq_term==last_term2) {
360                    do_below = 0;
361                }
362
363                ED4_species_name_terminal *name_term = seq_term->corresponding_species_name_terminal();
364                if (name_term->flag.selected) { // already selected
365                    if (xRangeChanged) {
366                        col_block_refresh_on_seq_term(seq_term);
367                    }
368                }
369                else { // select it
370                    ED4_species_manager *species_man = name_term->get_parent(ED4_L_SPECIES)->to_species_manager();
371
372                    if (!species_man->flag.is_consensus) {
373                        ED4_ROOT->add_to_selected(name_term);
374                    }
375                }
376            }
377            if (term==term2) {
378                break;
379            }
380            term = term->get_next_terminal();
381        }
382
383        if (!initial_call) {
384            if (do_below) {
385                while (term) {
386                    if (term->is_species_name_terminal() && term->flag.selected) {
387                        ED4_species_manager *species_man = term->get_parent(ED4_L_SPECIES)->to_species_manager();
388
389                        if (!species_man->flag.is_consensus) {
390                            ED4_ROOT->remove_from_selected(term);
391                        }
392                    }
393                    if (term==last_term2) break;
394                    term = term->get_next_terminal();
395                }
396            }
397
398            if (do_above) {
399                term = last_term1->corresponding_species_name_terminal();
400                while (term && term!=term1) {
401                    if (term->is_species_name_terminal() && term->flag.selected) {
402                        ED4_species_manager *species_man = term->get_parent(ED4_L_SPECIES)->to_species_manager();
403
404                        if (!species_man->flag.is_consensus) {
405                            ED4_ROOT->remove_from_selected(term);
406                        }
407                    }
408                    term = term->get_next_terminal();
409                }
410            }
411        }
412    }
413
414    last_term1 = term1;
415    last_term2 = term2;
416    last_pos1 = range_col1;
417    last_pos2 = range_col2;
418}
419
420void ED4_setColumnblockCorner(AW_event *event, ED4_sequence_terminal *seq_term) {
421    static ED4_sequence_terminal *fix_term = 0;
422    static ED4_index fix_pos = 0;
423
424    ED4_index seq_pos;
425    {
426        AW_pos termw_x, termw_y;
427        seq_term->calc_world_coords(&termw_x, &termw_y);
428
429        ED4_index scr_pos = ED4_ROOT->pixel2pos(event->x - termw_x);
430        ED4_remap *remap = ED4_ROOT->root_group_man->remap();
431        seq_pos = remap->screen_to_sequence(scr_pos);
432    }
433
434    switch (event->type) {
435        case AW_Mouse_Press: {
436            if (blocktype==ED4_BT_NOBLOCK) { // initial columnblock
437                ED4_setBlocktype(ED4_BT_COLUMNBLOCK);
438
439                fix_term = seq_term;
440                fix_pos = seq_pos;
441
442                select_and_update(fix_term, seq_term, fix_pos, seq_pos, 1);
443            }
444            else if (blocktype==ED4_BT_LINEBLOCK) { // change lineblock to columnblock
445                ED4_setBlocktype(ED4_BT_MODIFIED_COLUMNBLOCK);
446
447                fix_term = seq_term;
448                if (seq_pos<(MAXSEQUENCECHARACTERLENGTH/2)) { // in first half of sequence
449                    fix_pos = MAXSEQUENCECHARACTERLENGTH;
450                }
451                else {
452                    fix_pos = 0;
453                }
454
455                select_and_update(fix_term, seq_term, fix_pos, seq_pos, 1);
456            }
457            else { // expand columnblock (search nearest corner/border -> fix opposite corner/border)
458                e4_assert(blocktype==ED4_BT_COLUMNBLOCK || blocktype==ED4_BT_MODIFIED_COLUMNBLOCK);
459
460                ED4_list_elem *listElem = ED4_ROOT->selected_objects.first();
461                e4_assert(listElem);
462
463                if (blocktype==ED4_BT_COLUMNBLOCK) {
464                    AW_pos min_term_y = LONG_MAX;
465                    AW_pos max_term_y = LONG_MIN;
466                    ED4_species_name_terminal *min_term = 0;
467                    ED4_species_name_terminal *max_term = 0;
468                    AW_pos xpos, ypos;
469
470                    while (listElem) {
471                        ED4_selection_entry *selected = (ED4_selection_entry*)listElem->elem();
472                        ED4_species_name_terminal *name_term = selected->object->to_species_name_terminal();
473
474                        name_term->calc_world_coords(&xpos, &ypos);
475
476                        if (ypos<min_term_y) {
477                            min_term_y = ypos;
478                            min_term = name_term;
479                        }
480                        if (ypos>max_term_y) {
481                            max_term_y = ypos;
482                            max_term = name_term;
483                        }
484
485                        listElem = listElem->next();
486                    }
487
488                    seq_term->calc_world_coords(&xpos, &ypos);
489                    ED4_species_name_terminal *fix_name_term;
490                    if (fabs(ypos-min_term_y)<fabs(ypos-max_term_y)) { // seq_term is closer to min_term
491                        fix_name_term = max_term; // select max_term as fixed corner
492                    }
493                    else {
494                        fix_name_term = min_term;
495                    }
496                    e4_assert(fix_name_term);
497                    fix_term = fix_name_term->corresponding_sequence_terminal();
498                }
499
500                long scr_col1, scr_col2;
501                AW_screen_area area_rect;
502                {
503                    AW_pos ex = event->x;
504                    AW_pos ey = event->y;
505                    ED4_ROOT->world_to_win_coords(ED4_ROOT->get_ed4w()->aww, &ex, &ey);
506
507                    if (ED4_ROOT->get_area_rectangle(&area_rect, ex, ey)!=ED4_R_OK) {
508                        e4_assert(0);
509                        break;
510                    }
511                }
512
513
514                const ED4_remap *rm = ED4_ROOT->root_group_man->remap();
515
516                seq_term->calc_intervall_displayed_in_rectangle(&area_rect, &scr_col1, &scr_col2);
517                rm->clip_screen_range(&scr_col1, &scr_col2);
518
519                int range_scr_col1 = rm->sequence_to_screen(range_col1);
520                int range_scr_col2 = rm->sequence_to_screen(range_col2);
521                int scr_pos = rm->sequence_to_screen(seq_pos);
522
523                int use_scr_col1 = range_scr_col1<scr_col1 ? scr_col1 : range_scr_col1;
524                int use_scr_col2 = range_scr_col2>scr_col2 ? scr_col2 : range_scr_col2;
525
526                if (abs(scr_pos-use_scr_col1) < abs(scr_pos-use_scr_col2)) { // scr_pos is closer to use_scr_col1
527                    fix_pos = range_col2;
528                }
529                else {
530                    fix_pos = range_col1;
531                }
532
533                select_and_update(fix_term, seq_term, fix_pos, seq_pos, 0);
534            }
535            break;
536        }
537        case AW_Mouse_Drag: {
538            select_and_update(fix_term, seq_term, fix_pos, seq_pos, 0);
539            break;
540        }
541        case AW_Mouse_Release: {
542            select_and_update(fix_term, seq_term, fix_pos, seq_pos, 0);
543            break;
544        }
545        default: {
546            e4_assert(0);
547            break;
548        }
549    }
550}
551
552// --------------------------------------------------------------------------------
553//      Replace
554// --------------------------------------------------------------------------------
555
556static int strncmpWithJoker(GB_CSTR s1, GB_CSTR s2, int len) { // s2 contains '?' as joker
557    int cmp = 0;
558
559    while (len-- && !cmp) {
560        int c1 = *s1++;
561        int c2 = *s2++;
562
563        if (!c1) {
564            cmp = -1;
565        }
566        else if (!c2) {
567            cmp = 1;
568        }
569        else if (c2!='?') {
570            cmp = c1-c2;
571        }
572    }
573
574    return cmp;
575}
576
577static char *oldString, *newString;
578static int oldStringContainsJoker;
579
580static char* replace_in_sequence(const char *sequence, int len, int /* repeat */, int *new_len, GB_ERROR*) {
581    int maxlen;
582    int olen = strlen(oldString);
583    int nlen = strlen(newString);
584
585    if (nlen<=olen) {
586        maxlen = len;
587    }
588    else {
589        maxlen = (len/olen+1)*nlen;
590    }
591
592    char *new_seq = (char*)GB_calloc(maxlen+1, sizeof(*new_seq));
593    int replaced = 0;
594    int o = 0;
595    int n = 0;
596    char ostart = oldString[0];
597
598    if (oldStringContainsJoker) {
599        while (o<len) {
600            if (strncmpWithJoker(sequence+o, oldString, olen)==0) {
601                memcpy(new_seq+n, newString, nlen);
602                n += nlen;
603                o += olen;
604                replaced++;
605            }
606            else {
607                new_seq[n++] = sequence[o++];
608            }
609        }
610    }
611    else {
612        while (o<len) {
613            if (sequence[o]==ostart && strncmp(sequence+o, oldString, olen)==0) { // occurrence of oldString
614                memcpy(new_seq+n, newString, nlen);
615                n += nlen;
616                o += olen;
617                replaced++;
618            }
619            else {
620                new_seq[n++] = sequence[o++];
621            }
622        }
623    }
624    new_seq[n] = 0;
625
626    if (replaced) {
627        if (new_len) {
628            *new_len = n;
629        }
630    }
631    else {
632        delete new_seq;
633        new_seq = 0;
634    }
635
636    return new_seq;
637}
638
639static void replace_in_block(AW_window*) {
640    oldString = ED4_ROOT->aw_root->awar(ED4_AWAR_REP_SEARCH_PATTERN)->read_string();
641    newString = ED4_ROOT->aw_root->awar(ED4_AWAR_REP_REPLACE_PATTERN)->read_string();
642
643    oldStringContainsJoker = strchr(oldString, '?')!=0;
644    ED4_with_whole_block(replace_in_sequence, 1);
645
646    delete oldString; oldString = 0;
647    delete newString; newString = 0;
648}
649
650AW_window *ED4_create_replace_window(AW_root *root) {
651    AW_window_simple *aws = new AW_window_simple;
652
653    aws->init(root, "REPLACE", "Search & Replace");
654    aws->load_xfig("edit4/replace.fig");
655
656    aws->at("close");
657    aws->callback((AW_CB0)AW_POPDOWN);
658    aws->create_button("CLOSE", "Close", "C");
659
660    aws->at("help");
661    aws->callback(AW_POPUP_HELP, (AW_CL)"e4_replace.hlp");
662    aws->create_button("HELP", "Help", "H");
663
664    aws->at("spattern");
665    aws->create_input_field(ED4_AWAR_REP_SEARCH_PATTERN, 30);
666
667    aws->at("rpattern");
668    aws->create_input_field(ED4_AWAR_REP_REPLACE_PATTERN, 30);
669
670    aws->at("go");
671    aws->callback(replace_in_block);
672    aws->create_button("GO", "Go", "G");
673
674    return aws;
675}
676
677// --------------------------------------------------------------------------------
678//      Other block operations
679// --------------------------------------------------------------------------------
680
681static char *sequence_to_upper_case(const char *seq, int len, int /* repeat */, int *new_len, GB_ERROR*) {
682    char *new_seq = (char*)GB_calloc(len+1, sizeof(*new_seq));
683    int l;
684
685    for (l=0; l<len; l++) {
686        new_seq[l] = toupper(seq[l]);
687    }
688
689    if (new_len) *new_len = len;
690    return new_seq;
691}
692static char *sequence_to_lower_case(const char *seq, int len, int /* repeat */, int *new_len, GB_ERROR*) {
693    char *new_seq = (char*)GB_calloc(len+1, sizeof(*new_seq));
694    int l;
695
696    for (l=0; l<len; l++) {
697        new_seq[l] = tolower(seq[l]);
698    }
699
700    if (new_len) *new_len = len;
701    return new_seq;
702}
703
704#define EVEN_REPEAT "repeat-count is even -> no changes!"
705
706static char *reverse_sequence(const char *seq, int len, int repeat, int *new_len, GB_ERROR *error) {
707    if ((repeat&1)==0) { *error = GBS_global_string(EVEN_REPEAT); return 0; }
708
709    char *new_seq = GBT_reverseNucSequence(seq, len);
710    if (new_len) *new_len = len;
711    return new_seq;
712}
713static char *complement_sequence(const char *seq, int len, int repeat, int *new_len, GB_ERROR *error) {
714    if ((repeat&1)==0) {
715        *error = GBS_global_string(EVEN_REPEAT);
716        return 0;
717    }
718
719    char T_or_U;
720    *error = GBT_determine_T_or_U(ED4_ROOT->alignment_type, &T_or_U, "complement");
721    if (*error) return 0;
722
723    char *new_seq         = GBT_complementNucSequence(seq, len, T_or_U);
724    if (new_len) *new_len = len;
725    return new_seq;
726}
727static char *reverse_complement_sequence(const char *seq, int len, int repeat, int *new_len, GB_ERROR *error) {
728    if ((repeat&1) == 0) {
729        *error      = GBS_global_string(EVEN_REPEAT);
730        return 0;
731    }
732
733    char T_or_U;
734    *error = GBT_determine_T_or_U(ED4_ROOT->alignment_type, &T_or_U, "reverse-complement");
735    if (*error) return 0;
736    char *new_seq1  = GBT_complementNucSequence(seq, len, T_or_U);
737    char *new_seq2  = GBT_reverseNucSequence(new_seq1, len);
738
739    delete new_seq1;
740    if (new_len) *new_len = len;
741    return new_seq2;
742}
743
744static char *unalign_sequence_internal(const char *seq, int len, int *new_len, bool to_the_right) {
745    char *new_seq   = (char*)GB_calloc(len+1, sizeof(*new_seq));
746    int   o         = 0;
747    int   n         = 0;
748    char  gap       = '-';
749
750    if (to_the_right) {
751        if (ADPP_IS_ALIGN_CHARACTER(seq[0])) gap = seq[0]; // use first position of block if it's a gap
752        else if (ADPP_IS_ALIGN_CHARACTER(seq[-1])) gap = seq[-1]; // WARNING:  might be out-side sequence and undefined behavior
753    }
754    else {
755        if (ADPP_IS_ALIGN_CHARACTER(seq[len-1])) gap = seq[len-1]; // use first position of block if it's a gap
756        else if (ADPP_IS_ALIGN_CHARACTER(seq[len])) gap = seq[len]; // otherwise check position behind
757    }
758
759    while (o<len) {
760        if (!ADPP_IS_ALIGN_CHARACTER(seq[o])) new_seq[n++] = seq[o];
761        o++;
762    }
763
764    if (n<len) {                // (move and) dot rest
765        int gapcount = len-n;
766        if (to_the_right) {
767            memmove(new_seq+gapcount, new_seq, n);
768            memset(new_seq, gap, gapcount);
769        }
770        else {
771            memset(new_seq+n, gap, gapcount);
772        }
773    }
774
775    if (new_len) *new_len = len;
776    return new_seq;
777}
778
779static char *unalign_left_sequence(const char *seq, int len, int /* repeat */, int *new_len, GB_ERROR *) {
780    return unalign_sequence_internal(seq, len, new_len, false);
781}
782
783static char *unalign_right_sequence(const char *seq, int len, int /* repeat */, int *new_len, GB_ERROR *) {
784    return unalign_sequence_internal(seq, len, new_len, true);
785}
786
787static char *shift_left_sequence(const char *seq, int len, int repeat, int *new_len, GB_ERROR *error) {
788    char *new_seq = 0;
789
790    if (repeat>=len) {
791        *error = "Repeat count exceeds block length";
792    }
793    else
794    {
795        int enough_space = 1;
796        for (int i=0; enough_space && i<repeat; i++) {
797            if (!ADPP_IS_ALIGN_CHARACTER(seq[i])) {
798                enough_space = 0;
799            }
800        }
801
802        if (enough_space) {
803            char gap = '-';
804
805            new_seq               = (char*)GB_calloc(len+1, sizeof(*new_seq));
806            if (new_len) *new_len = len;
807            memcpy(new_seq, seq+repeat, len-repeat);
808
809            if (ADPP_IS_ALIGN_CHARACTER(seq[len-1])) gap    = seq[len-1];
810            else if (ADPP_IS_ALIGN_CHARACTER(seq[len])) gap = seq[len];
811
812            memset(new_seq+len-repeat, gap, repeat);
813        }
814        else {
815            *error = GBS_global_string("Shift left needs %i gap%s at block start", repeat, repeat==1 ? "" : "s");
816        }
817    }
818
819    return new_seq;
820}
821
822static char *shift_right_sequence(const char *seq, int len, int repeat, int *new_len, GB_ERROR *error) {
823    char *new_seq = 0;
824
825    if (repeat>=len) {
826        *error = "Repeat count exceeds block length";
827    }
828    else
829    {
830        int enough_space = 1;
831        for (int i=0; enough_space && i<repeat; i++) {
832            if (!ADPP_IS_ALIGN_CHARACTER(seq[len-i-1])) {
833                enough_space = 0;
834            }
835        }
836
837        if (enough_space) {
838            char gap = '-';
839
840            new_seq = (char*)GB_calloc(len+1, sizeof(*new_seq));
841            if (new_len) *new_len = len;
842
843            if (ADPP_IS_ALIGN_CHARACTER(seq[0])) gap       = seq[0];
844            else if (ADPP_IS_ALIGN_CHARACTER(seq[-1])) gap = seq[-1]; // a working hack
845
846            memset(new_seq, gap, repeat);
847            memcpy(new_seq+repeat, seq, len-repeat);
848        }
849        else {
850            *error = GBS_global_string("Shift right needs %i gap%s at block end", repeat, repeat==1 ? "" : "s");
851        }
852    }
853
854    return new_seq;
855}
856
857void ED4_perform_block_operation(ED4_blockoperation_type operationType) {
858    int nrepeat = ED4_ROOT->edit_string->use_nrepeat();
859
860    switch (operationType) {
861        case ED4_BO_UPPER_CASE:         ED4_with_whole_block(sequence_to_upper_case, nrepeat);          break;
862        case ED4_BO_LOWER_CASE:         ED4_with_whole_block(sequence_to_lower_case, nrepeat);          break;
863        case ED4_BO_REVERSE:            ED4_with_whole_block(reverse_sequence, nrepeat);                break;
864        case ED4_BO_COMPLEMENT:         ED4_with_whole_block(complement_sequence, nrepeat);             break;
865        case ED4_BO_REVERSE_COMPLEMENT: ED4_with_whole_block(reverse_complement_sequence, nrepeat);     break;
866        case ED4_BO_UNALIGN:            ED4_with_whole_block(unalign_left_sequence, nrepeat);           break;
867        case ED4_BO_UNALIGN_RIGHT:      ED4_with_whole_block(unalign_right_sequence, nrepeat);          break;
868        case ED4_BO_SHIFT_LEFT:         ED4_with_whole_block(shift_left_sequence, nrepeat);             break;
869        case ED4_BO_SHIFT_RIGHT:        ED4_with_whole_block(shift_right_sequence, nrepeat);            break;
870
871        default: {
872            e4_assert(0);
873            break;
874        }
875    }
876}
Note: See TracBrowser for help on using the repository browser.