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