source: tags/initial/EDIT4/ED4_search.cxx

Last change on this file was 2, checked in by oldcode, 23 years ago

Initial revision

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 48.8 KB
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <string.h>
4#include <limits.h>
5#include <ctype.h>
6#include <errno.h>
7
8#include <arbdb.h>
9#include <arbdbt.h>
10#include <aw_root.hxx>
11#include <aw_keysym.hxx>
12#include <aw_window.hxx>
13#include <aw_awars.hxx>
14#include <awtc_fast_aligner.hxx>
15#include <awt.hxx>
16
17#include "ed4_awars.hxx"
18#include "ed4_class.hxx"
19#include "ed4_tools.hxx"
20
21const char *ED4_SearchPositionTypeId[SEARCH_PATTERNS+1] =
22{
23    "User1", "User2",
24    "Probe",
25    "Primer (local)", "Primer (region)", "Primer (global)",
26    "Signature (local)", "Signature (region)", "Signature (global)",
27    "Any"
28};
29
30// --------------------------------------------------------------------------------
31
32typedef struct S_SearchAwarList // contains names of awars
33{
34    const char 
35        *pattern,
36        *min_mismatches,
37        *max_mismatches,
38        *case_sensitive,
39        *tu,
40        *pat_gaps,
41        *seq_gaps,
42        *reverse,
43        *complement,
44        *exact,
45        *show,
46        *openFolded,
47        *autoJump;
48   
49} *SearchAwarList;
50
51class SearchSettings
52{
53    char *pattern;
54    int min_mismatches;
55    int max_mismatches;
56    ED4_SEARCH_CASE case_sensitive;
57    ED4_SEARCH_TU tu;
58    ED4_SEARCH_GAPS pat_gaps;
59    ED4_SEARCH_GAPS seq_gaps;
60    int reverse;
61    int complement;
62    int exact;
63    int open_folded;
64    int autoJump;
65   
66    SearchSettings(const SearchSettings&) { e4_assert(0); } // forbidden
67   
68public:   
69   
70    void update(SearchAwarList awarList)
71    {
72        AW_root *root = ED4_ROOT->aw_root;
73       
74        delete pattern;
75        pattern = root->awar(awarList->pattern)->read_string();
76        min_mismatches = root->awar(awarList->min_mismatches)->read_int();
77        max_mismatches = root->awar(awarList->max_mismatches)->read_int();
78        case_sensitive = ED4_SEARCH_CASE(root->awar(awarList->case_sensitive)->read_int());
79        tu = ED4_SEARCH_TU(root->awar(awarList->tu)->read_int());
80        pat_gaps = ED4_SEARCH_GAPS(root->awar(awarList->pat_gaps)->read_int());
81        seq_gaps = ED4_SEARCH_GAPS(root->awar(awarList->seq_gaps)->read_int());
82        open_folded = root->awar(awarList->openFolded)->read_int();
83        autoJump = root->awar(awarList->autoJump)->read_int();
84        reverse = root->awar(awarList->reverse)->read_int();
85        complement = root->awar(awarList->complement)->read_int();
86        exact = root->awar(awarList->exact)->read_int();
87       
88        if (complement) {
89            if (IS_AMINO) {
90                complement = 0;
91                root->awar(awarList->complement)->write_int(0);
92                aw_message(GBS_global_string("Search for complement is not supported for this alignment type"), "Disable");
93            }
94        }       
95    }
96   
97    SearchSettings(SearchAwarList awarList)     { pattern = 0; update(awarList); }
98    ~SearchSettings()                           { delete pattern; }
99   
100    GB_CSTR get_pattern() const                 { return pattern; }
101    int get_min_mismatches() const              { return min_mismatches; }
102    int get_max_mismatches() const              { return max_mismatches; }
103    ED4_SEARCH_CASE get_case_sensitive() const  { return case_sensitive; }
104    ED4_SEARCH_TU get_tu() const                { return tu; }
105    ED4_SEARCH_GAPS get_pat_gaps() const        { return pat_gaps; }
106    ED4_SEARCH_GAPS get_seq_gaps() const        { return seq_gaps; }
107    int get_open_folded() const                 { return open_folded; }
108    int get_autoJump() const                    { return autoJump; }
109    int get_reverse() const                     { return reverse; }
110    int get_complement() const                  { return complement; }
111    int get_exact() const                       { return exact; }
112};
113
114// --------------------------------------------------------------------------------
115
116class SearchTree;
117typedef void (*reportMatch)(int start, int end, GB_CSTR comment, int mismatches[MAX_MISMATCHES]);
118
119class SearchTreeNode
120{
121    char c;                     // character
122    SearchTreeNode *son;        // son!=0 (exception: FOUND)
123    SearchTreeNode *brother;
124    char *comment;              // 0 or comment given in search pattern
125   
126    static SearchTreeNode FOUND;
127    static int start_offset;
128    static reportMatch report;
129    static int min_mismatches;
130    static int max_mismatches;
131    static int *uni2real;       // transform unified positions to real sequence positions
132   
133    SearchTreeNode(const SearchTreeNode &) { e4_assert(0); } // forbidden
134   
135public:
136   
137    SearchTreeNode(GB_CSTR pattern, GB_CSTR comment);
138    ~SearchTreeNode();
139   
140    SearchTreeNode *insert_unified_pattern(GB_CSTR pattern, GB_CSTR pattern_comment);
141    void findMatches(int off, GB_CSTR seq, int len, int mismatches, int mismatch_list[MAX_MISMATCHES]); 
142   
143    // you must call the following functions before calling findMatches():
144   
145    static void set_start_offset(int off)               { start_offset = off; }
146    static void set_report(reportMatch r, int *u2r)     { report = r; uni2real = u2r; } 
147    static void set_mismatches(int minMis, int maxMis)  { min_mismatches = minMis; max_mismatches = maxMis; } 
148};
149
150// --------------------------------------------------------------------------------
151
152SearchTreeNode  SearchTreeNode::FOUND(0, 0);   
153int             SearchTreeNode::start_offset;
154reportMatch     SearchTreeNode::report;
155int             SearchTreeNode::min_mismatches;
156int             SearchTreeNode::max_mismatches;
157int             *SearchTreeNode::uni2real;
158
159SearchTreeNode::SearchTreeNode(GB_CSTR pattern, GB_CSTR pattern_comment)
160{
161    comment = 0;
162    if (pattern) {
163        e4_assert(pattern[0]);
164        c = pattern[0];
165        if (pattern[1]) {
166            son = new SearchTreeNode(pattern+1, pattern_comment);
167        }
168        else {
169            son = &FOUND;
170            comment = GB_strdup(pattern_comment);
171        }
172    }
173    else { 
174        e4_assert(this==&FOUND);
175        c = 0;
176        son = 0;
177        comment = GB_strdup(pattern_comment);
178    }
179    brother = 0;
180}
181
182SearchTreeNode::~SearchTreeNode()
183{
184    if (brother!=&FOUND) delete brother;
185    if (son!=&FOUND) delete son;
186    delete comment;
187}
188
189
190SearchTreeNode *SearchTreeNode::insert_unified_pattern(GB_CSTR pattern, GB_CSTR pattern_comment)
191{
192    if (!this) {
193        if (pattern[0]) {
194            return new SearchTreeNode(pattern, pattern_comment);
195        }
196       
197        return &FOUND;
198    }
199   
200    if (this==&FOUND) {
201        if (pattern[0]) {
202            SearchTreeNode *neu = new SearchTreeNode(pattern, pattern_comment);
203           
204            neu->brother = &FOUND;
205            return neu;
206        }
207        return &FOUND;
208    }
209   
210    e4_assert(c);
211   
212    if (pattern[0]) { // pattern contains sth.
213        if (c==pattern[0]) {
214            e4_assert(son);
215            son = son->insert_unified_pattern(pattern+1, pattern_comment);
216        }
217        else {
218            if (brother) {
219                brother = brother->insert_unified_pattern(pattern, pattern_comment);
220            }
221            else {
222                brother = new SearchTreeNode(pattern, pattern_comment);
223            }
224        }
225    }
226    else { // empty pattern -> insert FOUND
227        if (brother) {
228            if (brother!=&FOUND) {
229                brother = brother->insert_unified_pattern(pattern, pattern_comment);
230            }
231        }
232        else {
233            brother = &FOUND;
234        }
235    }
236   
237    return this;
238}
239
240void SearchTreeNode::findMatches(int off, GB_CSTR seq, int len, int mismatches, int mismatch_list[MAX_MISMATCHES])
241{   
242    if (len) {
243        int matches = c=='?' || c==seq[0];
244        int use_mismatch = 0;
245       
246        if (!matches && mismatches<max_mismatches) { 
247            int c_is_gap = c=='-' || c=='.';
248            int seq_is_gap = seq[0]=='-' || seq[0]=='.';
249           
250            if (c_is_gap==seq_is_gap) {
251                mismatch_list[mismatches] = uni2real[off];
252                mismatches++;
253                use_mismatch = 1;
254                matches = 1;
255            }
256        }
257       
258        if (matches) {
259            if (son==&FOUND) {
260                if (mismatches>=min_mismatches) {
261                    report(uni2real[start_offset], uni2real[off], comment, mismatch_list);
262                }
263            }
264            else {
265                son->findMatches(off+1, seq+1, len-1, mismatches, mismatch_list);
266            }
267           
268            if (use_mismatch) {
269                mismatches--;
270                mismatch_list[mismatches] = -1;
271            }
272        }
273    }
274   
275    if (brother==&FOUND) {
276        if (mismatches>=min_mismatches) {
277            report(uni2real[start_offset], uni2real[off-1], comment, mismatch_list);
278        }
279    }
280    else if (brother) {
281        brother->findMatches(off, seq, len, mismatches, mismatch_list);
282    }
283}
284
285// --------------------------------------------------------------------------------
286
287class SearchTree
288{
289    const SearchSettings *sett;
290    SearchTreeNode *root;   
291    char unified[256];
292    int shortestPattern;
293   
294    static char unify_char(char c, int case_sensitive, int T_equal_U);
295   
296    char *unify_str(GB_CSTR data, int len, ED4_SEARCH_GAPS gaps, int *new_len, int **uni2real);
297    char *unify_pattern(GB_CSTR pattern, int *new_len);
298    char *unify_sequence(GB_CSTR sequence, int len, int *new_len, int **uni2real);
299   
300    SearchTree(const SearchTree &); // forbidden
301   
302public:
303   
304    SearchTree(const SearchSettings *s);
305    ~SearchTree();
306   
307    void findMatches(GB_CSTR seq, int len, reportMatch report);
308    int get_shortestPattern() const { return shortestPattern; }
309};
310
311// --------------------------------------------------------------------------------
312
313static char *shortenString(char *s)
314{
315    char *end = strchr(s, '\0');
316   
317    while (end>s && isspace(end[-1])) {
318        *--end = 0;
319    }
320    while (isspace(s[0])) {
321        s++;
322    }
323   
324    return s;
325}
326
327static void splitTokComment(char **tok, char **commentP)
328{
329    char *num = strchr(*tok, '#');
330   
331    if (num) {
332        num[0] = 0;
333        *commentP = shortenString(num+1);
334    }
335    else {
336        *commentP = 0;
337    }
338   
339    *tok = shortenString(*tok);
340}
341
342static char *appendComment(const char *s1, int l1, const char *s2) {
343    if (s1) {
344        int l2 = strlen(s2);
345        char *s = (char*)malloc(l1+1+l2+1);
346   
347        sprintf(s, "%s %s", s1, s2);
348        return s;
349    }
350   
351    return 0;
352}
353
354SearchTree::SearchTree(const SearchSettings *s) 
355{
356    sett = s;
357    root = 0;
358    shortestPattern = INT_MAX;
359   
360    {
361        int i;
362        int case_sensitive = (sett->get_case_sensitive()==ED4_SC_CASE_SENSITIVE);
363        int T_equal_U = (sett->get_tu()==ED4_ST_T_EQUAL_U);
364       
365        for (i=0; i<256; i++) {
366            unified[i] = unify_char(i, case_sensitive, T_equal_U);
367        }
368    }
369   
370#define ROOT(tok,com)                                                   \
371                do {                                                    \
372                    if (root) {                                         \
373                        root = root->insert_unified_pattern(tok, com);  \
374                    }                                                   \
375                    else {                                              \
376                        root = new SearchTreeNode(tok, com);            \
377                    }                                                   \
378                } while(0)                                             
379   
380    {
381        char *pattern = strdup(sett->get_pattern());
382        const char *trenner = "\n,";
383        char *tok = strtok(pattern, trenner);
384        char *comment;
385       
386        while (tok) {
387            splitTokComment(&tok, &comment);
388            int uni_tok_len;
389            char *uni_tok = unify_pattern(tok, &uni_tok_len);
390           
391            if (uni_tok[0]) {
392                int s_exact = sett->get_exact();
393                int s_reverse = sett->get_reverse();
394                int s_complement = sett->get_complement();
395               
396                if (uni_tok_len<shortestPattern) {
397                    shortestPattern = uni_tok_len;
398                }
399               
400                if (!s_exact || (!s_reverse && !s_complement)) {
401                    ROOT(uni_tok, comment);
402                }
403                int commentLen = comment ? strlen(comment) : 0;
404                   
405                if (s_reverse) {
406                    char *reverse = AWTC_reverseString(uni_tok, uni_tok_len);
407                    char *reverseComment = appendComment(comment, commentLen, "(reverse)");
408                   
409                    if (!s_exact || (s_reverse && !s_complement)) {
410                        ROOT(reverse, reverseComment);
411                    }
412                    if (s_complement) {
413                        e4_assert(IS_NUCLEOTIDE);
414                        char T_or_U = ED4_ROOT->alignment_type==GB_AT_DNA ? 'T' : 'U';
415                       
416                        char *revcomp = AWTC_complementString(reverse, uni_tok_len, T_or_U);
417                        char *revcompComment = appendComment(comment, commentLen, "(reverse complement)");
418                       
419                        if (!s_exact || (s_reverse && s_complement)) {
420                            ROOT(revcomp, revcompComment);
421                        }
422                        free(revcompComment);
423                        free(revcomp);
424                    }
425                       
426                    free(reverseComment);
427                    free(reverse);
428                }
429                else if (s_complement) {
430                    GB_alignment_type ali_type = GBT_get_alignment_type(gb_main, GBT_get_default_alignment(gb_main));
431                    e4_assert(ali_type==GB_AT_DNA || ali_type==GB_AT_RNA);
432                    char T_or_U = ali_type==GB_AT_DNA ? 'T' : 'U';
433                       
434                    char *complement = AWTC_complementString(uni_tok, uni_tok_len, T_or_U);
435                    char *complementComment = appendComment(comment, commentLen, "(complement)");
436                   
437                    if (!s_exact || (!s_reverse && s_complement)) {
438                        ROOT(complement, complementComment);
439                    }
440                    free(complementComment);
441                    free(complement);
442                }
443               
444            }
445           
446            tok = strtok(0, trenner);
447            free(uni_tok);
448        }               
449        free(pattern);
450    }
451               
452#undef ROOT             
453}
454
455SearchTree::~SearchTree()
456{
457    delete root;
458}
459
460char SearchTree::unify_char(char c, int case_sensitive, int T_equal_U)
461{
462    if (!case_sensitive) {
463        c = tolower(c);
464    }
465   
466    if (T_equal_U) {
467        if (c=='t') {
468            c = 'u';
469        }
470        else if (c=='T') {
471            c = 'U';
472        }
473    }
474   
475    if (c=='.') {
476        c = '-';
477    }
478   
479    return c;
480}
481
482char *SearchTree::unify_str(GB_CSTR data, int len, ED4_SEARCH_GAPS gaps, int *new_len, int **uni2real)
483{
484    char *p = (char*)malloc(len+1);
485   
486    if (!p) {
487        return 0;
488    }
489   
490    char *pp = p;
491    int nlen = 0;
492    int realPos = 0;
493   
494    // Original-Version:
495    //   
496    //     while (realPos<len) {
497    //  char c = *data++;
498    // 
499    //  if (gaps==ED4_SG_CONSIDER_GAPS || (c!='-' && c!='.')) { // use character in unified string?
500    //      *pp++ = unified[c];
501    //      if (uni2real) {
502    //          (*uni2real)[nlen] = realPos;
503    //      }
504    //      nlen++;
505    //  }
506    //  realPos++;
507    //     }
508    //   
509    // Optimized Version:   
510   
511    if (uni2real) {
512        int *u2r = *uni2real;
513       
514        if (gaps==ED4_SG_CONSIDER_GAPS) {
515            while(realPos<len) {
516                *pp++ = unified[data[realPos]];
517                u2r[nlen++] = realPos++;
518            }
519        }
520        else {
521            while(realPos<len) {
522                char c = data[realPos];
523           
524                if (c!='-' && c!='.') {
525                    *pp++ = unified[c];
526                    u2r[nlen++] = realPos;
527                }
528                realPos++;
529            }
530        }   
531    }
532    else {
533        if (gaps==ED4_SG_CONSIDER_GAPS) {
534            while(realPos<len) {
535                *pp++ = unified[data[realPos++]];
536                nlen++;
537            }
538        }
539        else {
540            while(realPos<len) {
541                char c = data[realPos++];
542           
543                if (c!='-' && c!='.') {
544                    *pp++ = unified[c];
545                    nlen++;
546                }
547            }
548        }   
549    }
550   
551    // ---------------   
552   
553    pp[0] = 0;
554    if (new_len) {
555        *new_len = nlen;
556    }
557    return p;
558}
559
560char *SearchTree::unify_pattern(GB_CSTR pattern, int *new_len)
561{
562    int len = strlen(pattern);
563    return unify_str(pattern, len, sett->get_pat_gaps(), new_len, 0);
564}
565
566char *SearchTree::unify_sequence(GB_CSTR sequence, int len, int *new_len, int **uni2real)
567{
568    return unify_str(sequence, len, sett->get_seq_gaps(), new_len, uni2real);
569}
570
571void SearchTree::findMatches(GB_CSTR seq, int len, reportMatch report)
572{
573    if (root) {
574        int new_len;
575        int *uni2real = (int*)malloc(len*sizeof(int));
576        char *uni_seq = uni2real ? unify_sequence(seq, len, &new_len, &uni2real) : 0;
577   
578        if (uni_seq) {
579            int off;
580            char *useq = uni_seq;
581            int mismatch_list[MAX_MISMATCHES];
582           
583            for (off=0; off<MAX_MISMATCHES; off++) {
584                mismatch_list[off] = -1;
585            }
586   
587            SearchTreeNode::set_report(report, uni2real);
588            SearchTreeNode::set_mismatches(sett->get_min_mismatches(), sett->get_max_mismatches());
589   
590            for (off=0; off<new_len; off++,useq++) {
591                SearchTreeNode::set_start_offset(off);
592                root->findMatches(off, useq, new_len-off, 0, mismatch_list);
593            }
594   
595            free(uni_seq);
596            free(uni2real);
597        }
598        else {
599            aw_message("Out of swapspace?", 0);
600            if (uni2real) free(uni2real);
601        }
602    }
603} 
604
605// --------------------------------------------------------------------------------
606
607#define AWAR_NAME(t,s)  ED4_AWAR_##t##_SEARCH_##s
608
609#define AWAR_LIST(t)                            \
610    AWAR_NAME(t,PATTERN),                       \
611    AWAR_NAME(t,MIN_MISMATCHES),                \
612    AWAR_NAME(t,MAX_MISMATCHES),                \
613    AWAR_NAME(t,CASE),                          \
614    AWAR_NAME(t,TU),                            \
615    AWAR_NAME(t,PAT_GAPS),                      \
616    AWAR_NAME(t,SEQ_GAPS),                      \
617    AWAR_NAME(t,REVERSE),                       \
618    AWAR_NAME(t,COMPLEMENT),                    \
619    AWAR_NAME(t,EXACT),                         \
620    AWAR_NAME(t,SHOW),                          \
621    AWAR_NAME(t,OPEN_FOLDED),                   \
622    AWAR_NAME(t,AUTO_JUMP)
623
624static struct S_SearchAwarList awar_list[SEARCH_PATTERNS] = {
625    { AWAR_LIST(USER1) },
626        { AWAR_LIST(USER2) },
627            { AWAR_LIST(PROBE) },
628                { AWAR_LIST(PRIMER1) },
629                    { AWAR_LIST(PRIMER2) },
630                        { AWAR_LIST(PRIMER3) },
631                            { AWAR_LIST(SIG1) },
632                                { AWAR_LIST(SIG2) },
633                                    { AWAR_LIST(SIG3) },
634                                        };
635
636static inline int resultsAreShown(ED4_SearchPositionType type)
637{
638    return ED4_ROOT->aw_root->awar(awar_list[type].show)->read_int();
639}
640
641enum search_params_changed_action {
642    REFRESH_IF_SHOWN    =1,
643    REFRESH_ALWAYS      =2,
644    RECALC_SEARCH_TREE  =4,
645    TEST_MIN_MISMATCH   =8,
646    TEST_MAX_MISMATCH   =16,
647    DO_AUTO_JUMP        =32
648};
649
650// --------------------------------------------------------------------------------
651
652static SearchSettings *settings[SEARCH_PATTERNS];       // last searched settings for each type
653static SearchTree *tree[SEARCH_PATTERNS];               // Search trees for each type
654
655// --------------------------------------------------------------------------------
656
657static void searchParamsChanged(AW_root *root, AW_CL cl_type, AW_CL cl_action)
658{
659    ED4_SearchPositionType type = ED4_SearchPositionType(cl_type);
660    enum search_params_changed_action action = (enum search_params_changed_action)cl_action;
661   
662    // check awar values
663   
664    if (action & (TEST_MIN_MISMATCH|TEST_MAX_MISMATCH)) {
665        int mimi = root->awar(awar_list[type].min_mismatches)->read_int();
666        int mami = root->awar(awar_list[type].max_mismatches)->read_int();
667       
668        if (mimi>mami) {
669            if (action & TEST_MIN_MISMATCH) { // max has changed
670                root->awar(awar_list[type].min_mismatches)->write_int(mami);
671            }
672            if (action & TEST_MAX_MISMATCH) { // min has changed
673                root->awar(awar_list[type].max_mismatches)->write_int(mimi);
674            }
675        }
676    }
677   
678    // init new search
679   
680 recalc:   
681    ED4_SearchResults::setNewSearch(type);
682    if (!settings[type]) return; 
683    settings[type]->update(&awar_list[type]);
684   
685    if (action & RECALC_SEARCH_TREE) {
686        delete tree[type];
687        tree[type] = new SearchTree(settings[type]);
688    }
689   
690    if (action & (RECALC_SEARCH_TREE|TEST_MIN_MISMATCH|TEST_MAX_MISMATCH)) {
691        if (tree[type]->get_shortestPattern() < 4*root->awar(awar_list[type].max_mismatches)->read_int()) {
692            aw_message("Too many mismatches!");
693            int mami = tree[type]->get_shortestPattern()/4;
694            root->awar(awar_list[type].max_mismatches)->write_int(mami);
695            if (root->awar(awar_list[type].min_mismatches)->read_int() > mami) {
696                root->awar(awar_list[type].min_mismatches)->write_int(mami);
697            }
698            goto recalc;
699        }
700    }
701   
702    if (action & REFRESH_IF_SHOWN) {
703        if (resultsAreShown(type)) {
704            action = (enum search_params_changed_action)(action|REFRESH_ALWAYS);
705        }
706    }
707   
708    if (settings[type]->get_autoJump() && (action & DO_AUTO_JUMP)) {            // auto jump
709        ED4_cursor *cursor = &ED4_ROOT->temp_ed4w->cursor;
710        int jumped = 0;
711       
712        if (cursor->owner_of_cursor && cursor->owner_of_cursor->is_sequence_terminal()) {
713            int pos = cursor->get_sequence_pos();
714            ED4_sequence_terminal *seq_term = cursor->owner_of_cursor->to_sequence_terminal();
715            ED4_SearchResults *result = &seq_term->results();
716           
717            result->search(seq_term);
718            ED4_SearchPosition *found = result->get_last_starting_before(type, pos+1, 0);
719            int bestPos = -1;
720           
721            if (found) {
722                bestPos = found->get_start_pos();
723            }
724           
725            if (pos>=1) {
726                found = result->get_first_starting_after(type, pos-1, 0);
727                if (found) {
728                    int next_pos = found->get_start_pos();
729                   
730                    if (abs(pos-next_pos)<abs(pos-bestPos)) {
731                        bestPos = next_pos;
732                    }
733                }
734            }
735           
736            if (bestPos!=-1) {
737                jumped = 1;
738                if (bestPos!=pos) {
739                    seq_term->setCursorTo(cursor, bestPos, 1);
740                }
741            }
742        }
743
744        if (!jumped) {
745            ED4_search(0, ED4_encodeSearchDescriptor(+1, type));
746        }
747    }
748   
749    if (action & REFRESH_ALWAYS) {
750        ED4_refresh_window(ED4_ROOT->temp_aww, 0, 0);
751    }
752}
753
754void ED4_create_search_awars(AW_root *root)
755{
756#define cb(action) add_callback(searchParamsChanged, AW_CL(i), AW_CL(action))
757   
758    int i;
759    for (i=0; i<SEARCH_PATTERNS; i++) {
760        root->awar_string(awar_list[i].pattern, "", gb_main)                            ->cb(REFRESH_IF_SHOWN | RECALC_SEARCH_TREE | DO_AUTO_JUMP);
761        root->awar_int(awar_list[i].case_sensitive, ED4_SC_CASE_INSENSITIVE, gb_main)   ->cb(REFRESH_IF_SHOWN | RECALC_SEARCH_TREE | DO_AUTO_JUMP);
762        root->awar_int(awar_list[i].tu, ED4_ST_T_EQUAL_U, gb_main)                      ->cb(REFRESH_IF_SHOWN | RECALC_SEARCH_TREE | DO_AUTO_JUMP);
763        root->awar_int(awar_list[i].pat_gaps, ED4_SG_IGNORE_GAPS, gb_main)              ->cb(REFRESH_IF_SHOWN | RECALC_SEARCH_TREE | DO_AUTO_JUMP);
764        root->awar_int(awar_list[i].reverse, 0, gb_main)                                ->cb(REFRESH_IF_SHOWN | RECALC_SEARCH_TREE | DO_AUTO_JUMP);
765        root->awar_int(awar_list[i].complement, 0, gb_main)                             ->cb(REFRESH_IF_SHOWN | RECALC_SEARCH_TREE | DO_AUTO_JUMP);
766        root->awar_int(awar_list[i].exact, 0, gb_main)                                  ->cb(REFRESH_IF_SHOWN | RECALC_SEARCH_TREE | DO_AUTO_JUMP);
767        root->awar_int(awar_list[i].min_mismatches, 0, gb_main)                         ->cb(REFRESH_IF_SHOWN | TEST_MAX_MISMATCH | DO_AUTO_JUMP);
768        root->awar_int(awar_list[i].max_mismatches, 0, gb_main)                         ->cb(REFRESH_IF_SHOWN | TEST_MIN_MISMATCH | DO_AUTO_JUMP);
769        root->awar_int(awar_list[i].seq_gaps, ED4_SG_IGNORE_GAPS, gb_main)              ->cb(REFRESH_IF_SHOWN | DO_AUTO_JUMP);
770        root->awar_int(awar_list[i].show, 1, gb_main)                                   ->cb(REFRESH_ALWAYS);
771        root->awar_int(awar_list[i].openFolded, 1, gb_main)                             ->cb(0);
772        root->awar_int(awar_list[i].autoJump, 1, gb_main)                               ->cb(DO_AUTO_JUMP);
773       
774        settings[i] = new SearchSettings(&awar_list[i]);
775        tree[i] = new SearchTree(settings[i]);
776    }
777   
778#undef cb
779   
780    // awars to save/load search parameters:
781   
782    root->awar_string(ED4_SEARCH_SAVE_BASE"/file_name", "noname.asp");
783    root->awar_string(ED4_SEARCH_SAVE_BASE"/filter", "asp");   
784   
785    {
786        GB_CSTR arbhome = GB_getenvARBHOME();
787        GB_CSTR sub = "/lib/search_settings";
788        char *buf = (char*)malloc(strlen(arbhome)+strlen(sub)+1);
789       
790        strcpy(buf, arbhome);
791        strcat(buf, sub);
792       
793        root->awar_string(ED4_SEARCH_SAVE_BASE"/directory", buf)->write_string(buf);
794    }
795}
796
797// --------------------------------------------------------------------------------
798
799char *ED4_SearchPosition::lastShownComment = 0;
800
801ED4_SearchPosition::ED4_SearchPosition(int sp, int ep, ED4_SearchPositionType wf, GB_CSTR found_comment, int mismatches[MAX_MISMATCHES])
802{
803    e4_assert(sp<=ep && sp>=0); // && ep<20000);
804    start_pos = sp;
805    end_pos = ep;
806    whatsFound = wf;
807    next = 0; 
808    comment = found_comment;
809    memcpy(mismatch, mismatches, sizeof(*mismatch)*MAX_MISMATCHES);
810}
811ED4_SearchPosition::ED4_SearchPosition(const ED4_SearchPosition& other) {
812    start_pos = other.start_pos;
813    end_pos = other.end_pos;
814    whatsFound = other.whatsFound;
815    next = 0;
816    comment = strdup(other.comment);
817    memcpy(mismatch, other.mismatch, sizeof(mismatch[0])*MAX_MISMATCHES);
818}
819
820ED4_SearchPosition *ED4_SearchPosition::insert(ED4_SearchPosition *toAdd)
821{
822    if (toAdd->cmp(*this)<=0) {
823        toAdd->next = this;
824        return toAdd;
825    }
826   
827    if (next) {
828        next = next->insert(toAdd);
829    }
830    else {
831        next = toAdd;
832    }
833   
834    return this;
835}
836ED4_SearchPosition *ED4_SearchPosition::remove(ED4_SearchPositionType typeToRemove)
837{
838    if (whatsFound==typeToRemove) {
839        ED4_SearchPosition *rest = next ? next->remove(typeToRemove) : 0;
840       
841        next = 0;
842        delete this;
843       
844        return rest;
845    }
846   
847    if (next) {
848        next = next->remove(typeToRemove);
849    }
850    return this;
851}
852
853#ifdef TEST_SEARCH_POSITION
854int ED4_SearchPosition::ok() const
855{
856#ifndef NDEBUG   
857    if (next) {
858        int c = cmp(*next);
859       
860        if (c>0) {
861            printf("ED4_SearchPosition: list not sorted\n");
862            return 0;
863        }
864       
865        return next->ok();
866    }
867#endif   
868    return 1;
869}
870#endif
871
872GB_CSTR ED4_SearchPosition::get_comment() const
873{
874    if (!comment) return 0;
875    if (lastShownComment && strcmp(lastShownComment, comment)==0) return 0;     // do not show comment twice
876   
877    delete lastShownComment;
878    lastShownComment = strdup(comment);
879    return lastShownComment;
880}
881
882ED4_SearchPosition *ED4_SearchPosition::get_next_at(int pos) const
883{
884    if (!next || next->start_pos>pos) {
885        return 0;
886    }
887    if (next->containsPos(pos)) {
888        return next;
889    }
890    return next->get_next_at(pos);
891}
892
893// --------------------------------------------------------------------------------
894
895int ED4_SearchResults::initialized = 0;
896int ED4_SearchResults::timeOfLastSearch[SEARCH_PATTERNS];
897int ED4_SearchResults::timeOfNextSearch[SEARCH_PATTERNS];
898int ED4_SearchResults::shown[SEARCH_PATTERNS];
899int ED4_SearchResults::bufferSize;
900char *ED4_SearchResults::buffer;
901
902ED4_SearchResults::ED4_SearchResults()
903{
904    if (!initialized) {
905        int i;
906       
907        for (i=0; i<SEARCH_PATTERNS; i++) {
908            timeOfLastSearch[i] = 0;
909            timeOfNextSearch[i] = 1;
910            shown[i] = resultsAreShown(ED4_SearchPositionType(i));
911        }
912       
913        bufferSize = 100;
914        buffer = (char*)GB_calloc(bufferSize, sizeof(char));
915       
916        initialized = 1;
917    }
918   
919    arraySize = 0; // list-format
920    array = 0;
921    first = 0;
922    int i;
923    for (i=0; i<SEARCH_PATTERNS; i++) {
924        timeOf[i] = 0;
925    }
926}
927
928// --------------------------------------------------------------------------------
929
930static ED4_SearchResults *reportToResult = 0;
931static ED4_SearchPositionType reportType;
932
933static void reportSearchPosition(int start, int end, GB_CSTR comment, int mismatches[MAX_MISMATCHES])
934{
935    ED4_SearchPosition *pos = new ED4_SearchPosition(start, end, reportType, comment, mismatches);
936    reportToResult->addSearchPosition(pos);
937}
938
939// --------------------------------------------------------------------------------
940
941void ED4_SearchResults::addSearchPosition(ED4_SearchPosition *pos)
942{
943    if (is_array()) {
944        to_list();
945    }
946       
947    if (first) {
948        first = first->insert(pos);
949#ifdef TEST_SEARCH_POSITION
950        e4_assert(first->ok());
951#endif 
952    }
953    else {
954        first = pos;
955    }
956}
957
958void ED4_SearchResults::search(ED4_sequence_terminal *seq_terminal)
959{
960    int i;
961    int needed[SEARCH_PATTERNS];
962    int st_needed = 0;
963   
964    for (i=0; i<SEARCH_PATTERNS; i++) {
965        if (timeOf[i]<timeOfNextSearch[i]) {
966            timeOf[i] = timeOfNextSearch[i]; 
967            timeOfLastSearch[i] = timeOfNextSearch[i];
968            needed[i] = 1;
969            st_needed = 1;
970            if (first) {
971                if (is_array()) {
972                    to_list();
973                }
974                first = first->remove(ED4_SearchPositionType(i));
975#ifdef TEST_SEARCH_POSITION             
976                e4_assert(!first || first->ok());
977#endif         
978            }
979        }
980        else {
981            needed[i] = 0;
982        }
983    }
984   
985    if (st_needed) {
986        int len;
987        char *seq = seq_terminal->resolve_pointer_to_string(&len);
988       
989        if (seq) {
990            reportToResult = this;
991            for (i=0; i<SEARCH_PATTERNS; i++) {
992                reportType = ED4_SearchPositionType(i);
993                if (needed[i]) {
994                    if (is_array()) {
995                        to_list();
996                    }
997                    tree[i]->findMatches(seq, len, reportSearchPosition);
998                }
999            }
1000            reportToResult = 0;
1001        }
1002    }
1003}
1004
1005ED4_SearchPosition *ED4_SearchResults::get_first_at(ED4_SearchPositionType type, int start, int end) const {
1006    if (is_list()) {
1007        to_array();
1008    }
1009   
1010    int l = 0;
1011    int h = arraySize-1;
1012   
1013    ED4_SearchPosition *pos = 0;
1014    int m = 0;
1015   
1016    while (l<=h) {
1017        m = (l+h)/2;
1018        pos = array[m];
1019        if (pos->get_end_pos()<start) {
1020            l = m+1;
1021        }
1022        else if (pos->get_start_pos()>end) {
1023            h = m-1;
1024        }
1025        else {
1026            e4_assert(pos->get_end_pos()>=start && pos->get_start_pos()<=end);
1027            break;
1028        }
1029    }
1030   
1031    if (l>h) {
1032        return 0;
1033    }
1034   
1035    if (pos) {
1036        int best_m = m;
1037       
1038        while (m>0) {
1039            m--;
1040            pos = array[m];
1041            if (pos->get_end_pos()>=start && pos->get_start_pos()<=end) {
1042                best_m = m;
1043            }
1044        }
1045        pos = array[best_m];
1046       
1047        while (pos) {
1048            if (type==ED4_ANY_PATTERN || pos->get_whatsFound()==type) {
1049                break;
1050            }
1051            pos = pos->get_next();
1052        }
1053       
1054        return pos;
1055    }
1056   
1057    return 0;
1058}
1059
1060ED4_SearchPosition *ED4_SearchResults::get_first_starting_after(ED4_SearchPositionType type, int pos, int mustBeShown) const
1061{
1062    ED4_SearchPosition *sp = first;
1063   
1064    while (sp) {
1065        if (type==ED4_ANY_PATTERN || sp->get_whatsFound()==type) {
1066            if (sp->get_start_pos()>pos && (!mustBeShown || resultsAreShown(sp->get_whatsFound()))) {
1067                break;
1068            }
1069        }
1070        sp = sp->get_next();
1071    }
1072   
1073    return sp;
1074}
1075
1076ED4_SearchPosition *ED4_SearchResults::get_last_starting_before(ED4_SearchPositionType type, int pos, int mustBeShown) const
1077{
1078    ED4_SearchPosition *sp = first,
1079        *best = 0;
1080   
1081    while (sp) {
1082        if (type==ED4_ANY_PATTERN || sp->get_whatsFound()==type) {
1083            if (sp->get_start_pos()<pos && (!mustBeShown || resultsAreShown(sp->get_whatsFound()))) {
1084                best = sp;
1085            }
1086            else {
1087                break;
1088            }
1089        }
1090        sp = sp->get_next();
1091    }
1092   
1093    return best;
1094}
1095
1096void ED4_SearchResults::setNewSearch(ED4_SearchPositionType type)
1097{
1098    if (type==ED4_ANY_PATTERN) {
1099        int i;
1100        for (i=0; i<SEARCH_PATTERNS; i++) {
1101            setNewSearch(ED4_SearchPositionType(i));
1102        }
1103    }
1104    else {
1105        int next_unused_stamp = timeOfLastSearch[type] + 1;
1106       
1107        shown[type] = resultsAreShown(type);
1108        if (timeOfNextSearch[type]!=next_unused_stamp) {
1109            timeOfNextSearch[type] = next_unused_stamp;
1110        }
1111    }
1112}
1113
1114void ED4_SearchResults::searchAgain()
1115{
1116    int i;
1117   
1118    for (i=0; i<SEARCH_PATTERNS; i++) {
1119        timeOf[i] = 0;
1120    }
1121}
1122
1123char *ED4_SearchResults::buildColorString(ED4_sequence_terminal *seq_terminal, int start, int end) 
1124    // builds a char buffer (access is only valid from result[start] till result[end])
1125{
1126    int i;
1127    int st_shown = 0;
1128   
1129    e4_assert(start<=end);
1130    for (i=0; i<SEARCH_PATTERNS; i++) {
1131        if (shown[i]) {
1132            st_shown = 1;
1133            break;
1134        }
1135    }
1136    if (!st_shown) {
1137        return 0; // nothing shown
1138    }
1139   
1140    search(seq_terminal);
1141    if (!get_first()) {
1142        return 0; // nothing found
1143    }
1144   
1145    int needed_size = end-start+1;
1146    if (needed_size>bufferSize) {
1147        free(buffer);
1148        bufferSize = needed_size;
1149        buffer = (char*)GB_calloc(bufferSize, sizeof(char));
1150    }
1151    else {
1152        memset(buffer, 0, sizeof(char)*needed_size);
1153    }
1154   
1155    // search first search-result that goes in between start-end
1156   
1157    ED4_SearchPosition *pos = get_first_at(ED4_ANY_PATTERN, start, end);
1158    //     while (pos && pos->get_end_pos()<start) {
1159    //  pos = pos->get_next();
1160    //     }
1161    e4_assert(!pos || (pos->get_start_pos()<=end && pos->get_end_pos()>=start));
1162   
1163    int correct_neg_values = 0;
1164   
1165    while (pos && pos->get_start_pos()<=end) {
1166        int what = int(pos->get_whatsFound());
1167       
1168        if (shown[what]) {
1169            int color = ED4_G_SBACK_0 + what;
1170            int s = max(pos->get_start_pos(), start)-start;
1171            int e = min(pos->get_end_pos(), end)-start;
1172       
1173            for (i=s; i<=e; i++) {
1174                if (buffer[i]==0 || abs(buffer[i])>abs(color)) {
1175                    buffer[i] = color;
1176                }
1177            }
1178           
1179            const int *mismatches = pos->getMismatches();
1180           
1181            for (i=0; i<5 && mismatches[i]>=0; i++) {
1182                int mpos = mismatches[i];
1183               
1184                if (mpos>=start && mpos<=end) {
1185                    int rpos = mpos-start;
1186                    if (buffer[rpos]==color) {
1187                        buffer[rpos] = -buffer[rpos];
1188                        correct_neg_values = 1;
1189                    }
1190                }
1191            }
1192        }
1193        pos = pos->get_next();
1194    }
1195   
1196    if (correct_neg_values) {
1197        for (i=end-start; i>=0; i--) {
1198            if (buffer[i]<0) {
1199                buffer[i] = ED4_G_MBACK;
1200            }
1201        }
1202    }
1203   
1204    return buffer-start;
1205}
1206
1207ED4_SearchPosition *ED4_SearchResults::get_shown_at(int pos) const
1208    // used by ED4_cursor::updateAwars to get search-comment
1209{
1210    ED4_SearchPosition *p = get_last_starting_before(ED4_ANY_PATTERN, pos, 0); // @@@ tofix: should find last_ending before
1211    ED4_SearchPosition *best = 0;
1212   
1213    if (!p) {
1214        p = get_first();
1215    }
1216   
1217    if (p && !p->containsPos(pos)) {
1218        p = p->get_next_at(pos);
1219    }
1220   
1221    while (p) {
1222        e4_assert(p->containsPos(pos));
1223        ED4_SearchPositionType type = p->get_whatsFound();
1224        if (shown[type]) {
1225            if (!best || type<best->get_whatsFound()) {
1226                best = p;
1227            }
1228        }
1229        p = p->get_next_at(pos);
1230    }
1231   
1232    return best;
1233}
1234
1235void ED4_SearchResults::to_array() const {
1236    e4_assert(arraySize==0); // assert list-format
1237   
1238    ED4_SearchPosition *pos = first;
1239   
1240    {
1241        int a_arraySize = 0;
1242       
1243        while (pos) {
1244            a_arraySize++;
1245            pos = pos->get_next();
1246        }
1247        *((int*)&arraySize) = a_arraySize;
1248    }
1249
1250    ED4_SearchPosition **a_array = (ED4_SearchPosition**)malloc(sizeof(ED4_SearchPosition*)*arraySize);
1251       
1252    int e;
1253    pos = first;
1254    for (e=0; e<arraySize; e++) {
1255        e4_assert(pos);
1256        a_array[e] = pos;
1257        pos = pos->get_next();
1258    }   
1259   
1260    *((ED4_SearchPosition***)&array) = a_array;
1261}
1262void ED4_SearchResults::to_list() const {
1263    e4_assert(arraySize>0); // assert array-format
1264    delete array;
1265   
1266    *((int*)&arraySize) = 0;
1267    *((ED4_SearchPosition***)&array) = 0;
1268}
1269
1270
1271// --------------------------------------------------------------------------------
1272
1273inline void decodeSearchDescriptor(int descriptor, int *direction, ED4_SearchPositionType *pattern)
1274{
1275    *direction = descriptor&1 ? 1 : -1;
1276    *pattern = ED4_SearchPositionType(descriptor/2);
1277}
1278
1279static AW_CL last_searchDescriptor = -1;
1280
1281GB_ERROR ED4_repeat_last_search(void) {
1282    if (int(last_searchDescriptor)==-1) {
1283        return GBS_global_string("You have to search first, before you can repeat a search.");
1284    }
1285   
1286    ED4_search(0, last_searchDescriptor);
1287    return 0;
1288}
1289
1290void ED4_search(AW_window */*aww*/, AW_CL searchDescriptor)
1291{
1292    int direction;
1293    ED4_SearchPositionType pattern;
1294    int searchOnlyForShownPatterns;
1295   
1296    last_searchDescriptor = searchDescriptor;
1297    decodeSearchDescriptor(searchDescriptor, &direction, &pattern);
1298    searchOnlyForShownPatterns = pattern==ED4_ANY_PATTERN;
1299   
1300    // detect position where to start searching
1301   
1302    ED4_terminal *terminal = 0; // start search at this terminal
1303    int pos; // ... and at this position
1304   
1305    ED4_cursor *cursor = &ED4_ROOT->temp_ed4w->cursor;
1306    if (cursor->owner_of_cursor) { // if cursor is shown -> use cursor position
1307        terminal = cursor->owner_of_cursor->to_terminal();
1308        pos = cursor->get_sequence_pos();
1309    }
1310    else { // start at end or beginning
1311        if (direction==1) {
1312            terminal = ED4_ROOT->root_group_man->get_first_terminal();
1313            pos = INT_MIN;
1314        }
1315        else {
1316            terminal = ED4_ROOT->root_group_man->get_last_terminal();
1317            pos = INT_MAX;
1318        }
1319    }
1320   
1321    ED4_terminal *start_terminal = terminal;
1322    int start_pos = pos;
1323    int last_loop = 0;
1324   
1325    while (terminal) {
1326        if (terminal->is_sequence_terminal()) {
1327            ED4_sequence_terminal *seq_terminal = terminal->to_sequence_terminal();
1328            ED4_SearchResults& results = seq_terminal->results();
1329            ED4_SearchPosition *found = 0;
1330           
1331            if (pattern==ED4_ANY_PATTERN || settings[pattern]->get_open_folded() || !terminal->is_in_folded_group()) {
1332                //              int done = 0;
1333               
1334                results.search(seq_terminal);
1335               
1336                if (direction==1) {
1337                    found = results.get_first_starting_after(pattern, pos, searchOnlyForShownPatterns);
1338                }
1339                else {
1340                    found = results.get_last_starting_before(pattern, pos, searchOnlyForShownPatterns);
1341                }
1342                   
1343                if (found) {
1344                    pos = found->get_start_pos();                       
1345                    if (terminal==start_terminal && pos==start_pos) {
1346                        if (searchOnlyForShownPatterns) {
1347                            aw_message("There are no other shown patterns");
1348                        }
1349                        else {
1350                            aw_message("This is the only occurance of the search pattern");
1351                        }
1352                    }
1353                    else {
1354                        seq_terminal->setCursorTo(&ED4_ROOT->temp_ed4w->cursor, pos, 1);
1355                    }
1356                    break;
1357                }
1358                else if (last_loop) {
1359                    if (searchOnlyForShownPatterns) {
1360                        aw_message("There are no shown patterns"); 
1361                    }
1362                    else {
1363                        aw_message("Search pattern was not found in any sequence");
1364                    }
1365                    break;
1366                }
1367            }
1368        }
1369       
1370        if (direction==1) {
1371            terminal = terminal->get_next_terminal();
1372            if (!terminal) terminal = ED4_ROOT->root_group_man->get_first_terminal();
1373            pos = INT_MIN;
1374        }
1375        else { 
1376            terminal = terminal->get_prev_terminal();
1377            if (!terminal) terminal = ED4_ROOT->root_group_man->get_last_terminal();
1378            pos = INT_MAX;
1379        }
1380       
1381        if (terminal==start_terminal) {
1382            last_loop = 1;
1383        }
1384    }
1385}
1386
1387#define ESC '\\'   
1388   
1389static char *pattern2str(GB_CSTR p) {
1390    char *s = GB_give_buffer(strlen(p)*2);
1391    char *s1 = s;
1392    GB_CSTR p1 = p;
1393   
1394    while (1) {
1395        char c = *p1++;
1396       
1397        if (!c) {
1398            break;
1399        }
1400        else if (c==ESC) {
1401            *s1++ = ESC;
1402            *s1++ = ESC;
1403        }
1404        else if (c=='\n') {
1405            *s1++ = ESC;
1406            *s1++ = 'n';
1407        }
1408        else {
1409            *s1++ = c;
1410        }
1411    }
1412   
1413    *s1 = 0;
1414    return strdup(s);
1415}
1416
1417static void str2pattern(char *s) { // works on string
1418    char *a = s;
1419    char *n = s;
1420   
1421    while (1) {
1422        char c = *a++;
1423       
1424        if (c==ESC) {
1425            c = *a++;
1426            if (c==ESC) {
1427                *n++ = ESC;
1428            }
1429            else if (c=='n') {
1430                *n++ = '\n';
1431            }
1432            else { // should not occur
1433                *n++ = ESC;
1434                *n++ = c;
1435            }
1436        }
1437        else {
1438            *n++ = c;
1439            if (!c) {
1440                break;
1441            }
1442        }
1443    }
1444}
1445
1446#undef ESC   
1447
1448static void save_search_paras_to_file(AW_window *aw, AW_CL cl_type) {
1449    AW_root *root = ED4_ROOT->aw_root;
1450    ED4_SearchPositionType type = ED4_SearchPositionType(cl_type);
1451    char *filename = root->awar(ED4_SEARCH_SAVE_BASE"/file_name")->read_string();
1452    FILE *in = fopen(filename, "rt");
1453   
1454    if (in) {
1455        fclose(in);
1456        GB_CSTR error = GBS_global_string("'%s' already exists", filename);
1457        int answer = aw_message(error, "Overwrite,Cancel");
1458        if (answer!=0) {
1459            return;
1460        }
1461    }
1462   
1463    FILE *out = fopen(filename, "wt");
1464   
1465    if (!out) {
1466        GB_CSTR error = GBS_global_string("Can't write file '%s' (%s)", filename, strerror(errno));
1467        aw_message(error, "OK");
1468    }
1469    else {
1470        SearchSettings *s = settings[type];
1471       
1472        char *fpat = pattern2str(s->get_pattern());
1473       
1474        fprintf(out,
1475                "pattern=%s\n"
1476                "minmis=%i\n"
1477                "maxmis=%i\n"
1478                "case=%i\n"
1479                "tu=%i\n"
1480                "patgaps=%i\n"
1481                "seqgaps=%i\n"
1482                "openfolded=%i\n"
1483                "autojump=%i\n"
1484                "reverse=%i\n"
1485                "complement=%i\n"
1486                "exact=%i\n",
1487                fpat,
1488                s->get_min_mismatches(),
1489                s->get_max_mismatches(),
1490                s->get_case_sensitive(),
1491                s->get_tu(),
1492                s->get_pat_gaps(),
1493                s->get_seq_gaps(),
1494                s->get_open_folded(),
1495                s->get_autoJump(),
1496                s->get_reverse(),
1497                s->get_complement(),
1498                s->get_exact());
1499       
1500        free(fpat);
1501        fclose(out);
1502    }
1503    AW_POPDOWN(aw);
1504}
1505
1506static void load_search_paras_from_file(AW_window *aw, AW_CL cl_type) {
1507    AW_root *root = ED4_ROOT->aw_root;
1508    ED4_SearchPositionType type = ED4_SearchPositionType(cl_type);
1509    char *filename = root->awar(ED4_SEARCH_SAVE_BASE"/file_name")->read_string();
1510    FILE *in = fopen(filename, "rt");
1511   
1512    if (!in) {
1513        GB_CSTR error = GBS_global_string("File '%s' not found", filename);
1514        aw_message(error, "Oops.. sorry!");
1515        return;
1516    }
1517   
1518#define BUFFERSIZE 10000
1519   
1520    SearchAwarList al = &awar_list[type];
1521    while(1) {
1522        char buffer[BUFFERSIZE];
1523       
1524        buffer[0] = 0;
1525        fgets(buffer, BUFFERSIZE, in);
1526        if (!buffer[0]) {
1527            break;
1528        }
1529        char *content = strchr(buffer, '=');
1530        if (!content) {
1531            aw_message(GBS_global_string("Format error in '%s' - ignored!", filename));
1532            continue;
1533        }
1534        *content++ = 0;
1535       
1536        if (strcmp(buffer, "pattern")==0) {
1537            str2pattern(content);
1538            root->awar(al->pattern)->write_string(content);
1539        }
1540        else {
1541            int value = atoi(content);
1542           
1543            if (strcmp(buffer, "minmis")==0)            root->awar(al->min_mismatches)->write_int(value);
1544            else if (strcmp(buffer, "maxmis")==0)       root->awar(al->max_mismatches)->write_int(value);
1545            else if (strcmp(buffer, "case")==0)         root->awar(al->case_sensitive)->write_int(value);
1546            else if (strcmp(buffer, "tu")==0)           root->awar(al->tu)->write_int(value);
1547            else if (strcmp(buffer, "patgaps")==0)      root->awar(al->pat_gaps)->write_int(value);
1548            else if (strcmp(buffer, "seqgaps")==0)      root->awar(al->seq_gaps)->write_int(value);
1549            else if (strcmp(buffer, "openfolded")==0)   root->awar(al->openFolded)->write_int(value);
1550            else if (strcmp(buffer, "autojump")==0)     root->awar(al->autoJump)->write_int(value);
1551            else if (strcmp(buffer, "reverse")==0)      root->awar(al->reverse)->write_int(value);
1552            else if (strcmp(buffer, "complement")==0)   root->awar(al->complement)->write_int(value);
1553            else if (strcmp(buffer, "exact")==0)        root->awar(al->exact)->write_int(value);
1554            else {
1555                aw_message(GBS_global_string("Unknown tag '%s' in '%s' - ignored!", buffer, filename));
1556            }
1557        }
1558    }
1559
1560#undef BUFFERSIZE
1561   
1562    fclose(in);
1563    AW_POPDOWN(aw);
1564}
1565
1566static AW_window *loadsave_search_parameters(AW_root *root, ED4_SearchPositionType type, int load) {
1567    AW_window_simple *aws = new AW_window_simple;
1568   
1569    if (load) {
1570        ED4_aws_init(root, aws, "load_%s_search_para", "Load %s Search Parameters", ED4_SearchPositionTypeId[type]);
1571    }
1572    else {
1573        ED4_aws_init(root, aws, "save_%s_search_para", "Save %s Search Parameters", ED4_SearchPositionTypeId[type]);
1574    }
1575   
1576    aws->load_xfig("edit4/save_search.fig");
1577
1578    aws->at("close");aws->callback((AW_CB0)AW_POPDOWN);
1579    aws->create_button("CLOSE","CLOSE","C");                       
1580
1581    aws->callback( AW_POPUP_HELP, (AW_CL)"search_parameters.hlp");
1582    aws->at("help");
1583    aws->create_button("HELP","HELP","H");                         
1584
1585    awt_create_selection_box((AW_window *)aws, ED4_SEARCH_SAVE_BASE);
1586
1587    aws->callback( (AW_CB0)AW_POPDOWN);
1588    aws->at("cancel");
1589    aws->create_button("CANCEL","CANCEL","C");
1590
1591    aws->at("save");
1592    if (load) {
1593        aws->callback(load_search_paras_from_file, (AW_CL)type);
1594        aws->create_button("LOAD","LOAD","L");                     
1595    }
1596    else {
1597        aws->callback(save_search_paras_to_file, (AW_CL)type);
1598        aws->create_button("SAVE","SAVE","S");                     
1599    }
1600   
1601    return aws;
1602}
1603
1604static AW_window *load_search_parameters(AW_root *root, AW_CL cl_type) {
1605    return loadsave_search_parameters(root, ED4_SearchPositionType(cl_type), 1);
1606}
1607
1608static AW_window *save_search_parameters(AW_root *root, AW_CL cl_type) {
1609    return loadsave_search_parameters(root, ED4_SearchPositionType(cl_type), 0);
1610}
1611
1612
1613AW_window *ED4_create_search_window(AW_root *root, AW_CL cl) {
1614    ED4_SearchPositionType type = ED4_SearchPositionType(cl);
1615    SearchAwarList awarList = &awar_list[type];
1616    AW_window_simple *aws = new AW_window_simple;
1617   
1618    ED4_aws_init(root, aws, "%s_search", "%s Search", ED4_SearchPositionTypeId[type]);
1619    aws->load_xfig("edit4/search.fig");
1620   
1621    aws->at("close");
1622    aws->callback( (AW_CB0)AW_POPDOWN);
1623    aws->create_button("CLOSE", "CLOSE","C");
1624       
1625    aws->at("help");
1626    aws->callback( AW_POPUP_HELP,(AW_CL)"e4_search.hlp");
1627    aws->create_button("HELP", "HELP","H");
1628   
1629    aws->at("load");
1630    aws->callback(AW_POPUP, (AW_CL)load_search_parameters, (AW_CL)type);
1631    aws->create_button("LOAD", "LOAD", "L");
1632
1633    aws->at("save");
1634    aws->callback(AW_POPUP, (AW_CL)save_search_parameters, (AW_CL)type);
1635    aws->create_button("SAVE", "SAVE", "S");
1636
1637    aws->at("next");
1638    aws->callback(ED4_search, (AW_CL)ED4_encodeSearchDescriptor(+1, type));
1639    aws->create_button("SEARCH_NEXT", "#edit/next.bitmap", "N");
1640   
1641    aws->at("previous");
1642    aws->callback(ED4_search, (AW_CL)ED4_encodeSearchDescriptor(-1, type));
1643    aws->create_button("SEARCH_LAST", "#edit/last.bitmap", "L");
1644   
1645    aws->at("show");
1646    aws->create_toggle(awarList->show); 
1647   
1648    aws->at("open");
1649    aws->create_toggle(awarList->openFolded); 
1650   
1651    aws->at("jump");
1652    aws->create_toggle(awarList->autoJump); 
1653   
1654    aws->at("pattern");
1655    aws->create_text_field(awarList->pattern, 28, 17);
1656   
1657    aws->at("minmis");
1658    aws->create_toggle_field(awarList->min_mismatches, 1);     
1659    aws->insert_default_toggle("0", "0", 0);
1660    aws->insert_toggle("1", "1", 1);
1661    aws->insert_toggle("2", "2", 2);
1662    aws->update_toggle_field();   
1663   
1664    aws->at("maxmis");
1665    aws->create_toggle_field(awarList->max_mismatches, 1);     
1666    aws->insert_default_toggle("0", "0", 0);
1667    aws->insert_toggle("1", "1", 1);
1668    aws->insert_toggle("2", "2", 2);
1669    aws->insert_toggle("3", "3", 3);
1670    aws->insert_toggle("4", "4", 4);
1671    aws->insert_toggle("5", "5", 5);
1672    aws->update_toggle_field();   
1673   
1674    aws->at("seq_gaps");
1675    aws->create_toggle(awarList->seq_gaps);
1676    aws->at("pat_gaps");
1677    aws->create_toggle(awarList->pat_gaps);
1678    aws->at("tu");
1679    aws->create_toggle(awarList->tu);
1680    aws->at("case");
1681    aws->create_toggle(awarList->case_sensitive);
1682    aws->at("reverse");
1683    aws->create_toggle(awarList->reverse); 
1684    aws->at("complement");
1685    aws->create_toggle(awarList->complement);
1686    aws->at("exact");
1687    aws->create_toggle(awarList->exact);
1688   
1689   
1690    return (AW_window *)aws;
1691}
Note: See TracBrowser for help on using the repository browser.