source: branches/profile/ARB_GDE/GDE_event.cxx

Last change on this file was 12834, checked in by westram, 10 years ago
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 28.4 KB
Line 
1#include "GDE_extglob.h"
2#include "GDE_awars.h"
3
4#include <awt_filter.hxx>
5#include <aw_window.hxx>
6#include <aw_root.hxx>
7#include <aw_question.hxx>
8#include <aw_awar.hxx>
9#include <aw_msg.hxx>
10#include <aw_file.hxx>
11#include <arb_progress.h>
12#include <AP_filter.hxx>
13
14#include <set>
15#include <string>
16
17#include <unistd.h>
18
19using namespace std;
20
21extern adfiltercbstruct *agde_filter;
22
23/*
24  ReplaceArgs():
25  Replace all command line arguments with the appropriate values
26  stored for the chosen menu item.
27
28  Copyright (c) 1989-1990, University of Illinois board of trustees.  All
29  rights reserved.  Written by Steven Smith at the Center for Prokaryote Genome
30  Analysis.  Design and implementation guidance by Dr. Gary Olsen and Dr.
31  Carl Woese.
32
33  Copyright (c) 1990,1991,1992 Steven Smith at the Harvard Genome Laboratory.
34  All rights reserved.
35
36*/
37
38
39static char *ReplaceArgs(AW_root *awr, char *Action, GmenuItem *gmenuitem, int number)
40{
41    /*
42     *  The basic idea is to replace all of the symbols in the method
43     *  string with the values picked in the dialog box.  The method
44     *  is the general command line structure.  All arguments have two
45     *  parts : a label and a value.  Values are the
46     *  associated arguments that some flags require.  All symbols that
47     *  require argvalue replacement should have a '$' infront of the symbol
48     *  name in the itemmethod definition.
49     *
50     *  If '$symbol' is prefixed by '!' ARB_GDE does a label replacement, i.e. insert
51     *  the value visible in GUI. Only works for argchoice arguments!
52     *  This is intended for informational use (e.g. to write used settings
53     *  into the comment of a generated tree).
54     *
55     *  An example command line replacement would be:
56     *
57     *       itemmethod=>        "lpr -P $arg1 $arg2"
58     *
59     *       arglabel arg1=>     "To printer?"
60     *       argvalue arg1=>     "lw"
61     *
62     *       arglabel arg2=>     "File name?"
63     *       argvalue arg2=>     "foobar"
64     *
65     *   final command line:
66     *
67     *       lpr -P lw foobar
68     *
69     */
70
71    char       *textvalue  = 0;
72    const char *labelvalue = 0;
73
74    GmenuItemArg& currArg = gmenuitem->arg[number];
75
76    const char *symbol = currArg.symbol;
77    int         type   = currArg.type;
78
79    if (type == SLIDER) {
80        char *awarname = GDE_makeawarname(gmenuitem, number);
81        textvalue      = awr->awar(awarname)->read_as_string();
82        free(awarname);
83    }
84    else if (type == FILE_SELECTOR) {
85        char *awar_base = GDE_maketmpawarname(gmenuitem, number);
86        textvalue  = AW_get_selected_fullname(awr, awar_base);
87        free(awar_base);
88    }
89    else if (type == CHOOSER ||
90             type == CHOICE_TREE ||
91             type == CHOICE_SAI ||
92             type == CHOICE_MENU ||
93             type == CHOICE_LIST ||
94             type == CHOICE_WEIGHTS ||
95             type == TEXTFIELD)
96    {
97        char *awarname = GDE_makeawarname(gmenuitem, number);
98        textvalue      = awr->awar(awarname)->read_string();
99
100        if (currArg.choice) {
101            for (int c = 0; c<currArg.numchoices && !labelvalue; ++c) {
102                GargChoice& choice = currArg.choice[c];
103                if (choice.method) {
104                    if (strcmp(choice.method, textvalue) == 0) {
105                        labelvalue = choice.label;
106                    }
107                }
108            }
109        }
110    }
111
112    if (textvalue == NULL)  textvalue=(char *)calloc(1, sizeof(char));
113    if (symbol == NULL)     symbol="";
114
115    set<string>warned_about;
116    int conversion_warning = 0;
117   
118    for (int i, j = 0; (i=Find2(Action+j, symbol)) != -1;) {
119        i += j;
120        ++j;
121        if (i>0 && Action[i-1] == '$') {
122            const char *replaceBy = textvalue;
123            int         skip      = 1;
124
125            if (i>1 && Action[i-2] == '!') { // use label (if available)
126                if (labelvalue) {
127                    replaceBy = labelvalue;
128                    skip = 2; // skip '!'
129                }
130                else {
131                    aw_message(GBS_global_string("[ARB_GDE]: Cannot access label of '%s'\n", symbol));
132                    return NULL; // @@@ ignores resources (should only occur during development)
133                }
134            }
135
136            int   repLen = strlen(replaceBy);
137            int   symLen = strlen(symbol);
138            int   newlen = strlen(Action)-skip-symLen+repLen+1;
139            char *temp   = (char *)calloc(newlen, 1);
140
141            strncat(temp, Action, i-skip);
142            strncat(temp, replaceBy, repLen);
143            strcat(temp, &(Action[i+symLen]));
144            freeset(Action, temp);
145        }
146        else {
147            if (warned_about.find(symbol) == warned_about.end()) {
148                fprintf(stderr,
149                        "old arb version converted '%s' to '%s' (now only '$%s' is converted)\n",
150                        symbol, textvalue, symbol);
151                conversion_warning++;
152                warned_about.insert(symbol);
153            }
154        }
155    }
156
157    if (conversion_warning) {
158        fprintf(stderr,
159                "Conversion warnings occurred in Action:\n'%s'\n",
160                Action);
161    }
162
163    free(textvalue);
164    return (Action);
165}
166
167static char *ReplaceFile(char *Action, GfileFormat file)
168{
169    char *symbol, *method, *temp;
170    int i, newlen;
171    symbol = file.symbol;
172    method = file.name;
173
174    for (; (i=Find2(Action, symbol)) != -1;)
175    {
176        newlen = strlen(Action)-strlen(symbol) + strlen(method)+1;
177        temp = (char *)calloc(newlen, 1);
178        strncat(temp, Action, i);
179        strncat(temp, method, strlen(method));
180        strcat(temp, &(Action[i+strlen(symbol)]));
181        freeset(Action, temp);
182    }
183    return (Action);
184}
185
186static char *ReplaceString(char *Action, const char *old, const char *news)
187{
188    const char *symbol;
189    const char *method;
190    char *temp;
191    int i, newlen;
192
193    symbol = old;
194    method = news;
195
196    for (; (i=Find2(Action, symbol)) != -1;)
197    {
198        newlen = strlen(Action)-strlen(symbol) + strlen(method)+1;
199        temp = (char *)calloc(newlen, 1);
200        strncat(temp, Action, i);
201        strncat(temp, method, strlen(method));
202        strcat(temp, &(Action[i+strlen(symbol)]));
203        freeset(Action, temp);
204    }
205    return (Action);
206}
207
208static void GDE_freesequ(NA_Sequence *sequ) {
209    if (sequ) {
210        freenull(sequ->comments);
211        freenull(sequ->baggage);
212        freenull(sequ->sequence);
213    }
214}
215
216NA_Alignment::NA_Alignment(GBDATA *gb_main_) {
217    memset(this, 0, sizeof(*this));
218
219    gb_main = gb_main_;
220    {
221        GB_transaction ta(gb_main);
222        alignment_name = GBT_get_default_alignment(gb_main);
223        alignment_type = GBT_get_alignment_type(gb_main, alignment_name);
224    }
225}
226
227NA_Alignment::~NA_Alignment() {
228    free(id);
229    free(description);
230    free(authority);
231    free(alignment_name);
232
233    for (unsigned long i=0; i<numelements; i++) {
234        GDE_freesequ(element+i);
235    }
236}
237
238static GB_ERROR write_sequence_autoinc_alisize(GBDATA *gb_data, long& ali_len, const char *sequence, int seq_len) {
239    /* writes sequence data.
240     * Specials things done:
241     * - cuts content beyond 'ali_len' if nothing relevant there
242     * - increments alignment length (stored in DB and parameter)
243     */
244
245    GB_ERROR error    = 0;
246    int      part_len = seq_len; // size that will be written
247    if (seq_len > ali_len) { // sequence longer than alignment
248        // check whether it can be cutoff w/o loosing anything relevant
249        int oversize          = seq_len-ali_len;
250        int irrelevant        = strspn(sequence+ali_len, "-.nN"); // @@@ this has to be different for AA!
251        int relevant_oversize = oversize-irrelevant;
252
253        part_len = ali_len+relevant_oversize;
254
255        if (relevant_oversize) { // got some relevant data behind alignment length -> increase alignment length
256            int         new_ali_len = part_len;
257            GBDATA     *gb_main     = GB_get_root(gb_data);
258            const char *ali_name    = GB_read_key_pntr(GB_get_father(gb_data));
259
260            gde_assert(GBT_get_alignment_len(gb_main, ali_name) == ali_len);
261
262            error   = GBT_set_alignment_len(gb_main, ali_name, new_ali_len);
263            ali_len = new_ali_len;
264        }
265    }
266
267    if (!error) {
268        if (part_len<seq_len) {
269            char *seq_part = GB_strndup(sequence, part_len);
270            error = GB_write_string(gb_data, seq_part);
271            free(seq_part);
272        }
273        else {
274            gde_assert(part_len == seq_len);
275            error = GB_write_string(gb_data, sequence);
276        }
277    }
278
279    return error;
280}
281
282inline bool isgap(char c) { return c == '.' || c == '-'; }
283inline bool isTU(char c) { return c == 'T' || c == 'U'; }
284
285inline char eatgaps(const char *seq, int& index) {
286    /*! increments index forward to next base (or EOS)
287     * @return first gap char seen or 0
288     */
289    if (isgap(seq[index])) {
290        char gap = seq[index++];
291        while (isgap(seq[index])) ++index;
292        return gap;
293    }
294    return 0;
295}
296
297static char *fix_aligned_data(const char *old_seq, const char *new_seq, GB_alignment_type ali_type) {
298    char *fixed = strdup(new_seq);
299
300    int o = 0;
301    int n = 0;
302    int f = 0;
303
304    bool fixTU = ali_type == GB_AT_RNA || ali_type == GB_AT_DNA;
305    char TU    = ali_type == GB_AT_RNA ? 'U' : 'T';
306    char tu    = tolower(TU);
307
308    while (old_seq[o]) {
309        char og = eatgaps(old_seq, o);
310        char ng = eatgaps(new_seq, n);
311
312        if (og && ng && og != ng) memset(fixed+f, og, n-f);
313        f = n;
314
315        char oc = old_seq[o++];
316        char nc = new_seq[n++];
317        if (!nc) break;
318
319        char oC = toupper(oc);
320        char nC = toupper(nc);
321
322        if (fixTU && isTU(nC) && isTU(oC)) fixed[f] = (oc == oC) ? TU : tu;
323        else if (oc != nc && oC == nC)     fixed[f] = oc;
324
325        f++;
326    }
327
328    return fixed;
329}
330
331static void export_to_DB(NA_Alignment& dataset, size_t oldnumelements, bool aligned_data) {
332    /*! (re-)import data into arb DB
333     * @param dataset normally has been read from file (which was created by external tool)
334     * @param oldnumelements start index into dataset
335     * @param aligned_data if true => only import sequences; expect checksums did not change; repair some minor, unwanted changes (case, T<>U, gaptype)
336     */
337    if (dataset.numelements == oldnumelements) return;
338    gde_assert(dataset.numelements > oldnumelements); // otherwise this is a noop
339
340    GBDATA     *gb_main     = db_access.gb_main;
341    GB_ERROR    error       = GB_begin_transaction(gb_main);
342    const char *ali_name    = dataset.alignment_name;
343    long        maxalignlen = GBT_get_alignment_len(gb_main, ali_name);
344
345    if (maxalignlen <= 0 && !error) {
346        error = GB_await_error();
347    }
348
349    long lotyp = 0;
350    if (!error) {
351        GB_alignment_type at = GBT_get_alignment_type(gb_main, ali_name);
352
353        switch (at) {
354            case GB_AT_DNA:     lotyp = DNA;     break;
355            case GB_AT_RNA:     lotyp = RNA;     break;
356            case GB_AT_AA:      lotyp = PROTEIN; break;
357            case GB_AT_UNKNOWN: lotyp = DNA;     break;
358        }
359    }
360
361    unsigned long i;
362    const long    oldalignlen = maxalignlen;
363    bool          auto_format = false;
364
365    AW_repeated_question overwrite_question;
366    AW_repeated_question checksum_change_question;
367
368    arb_progress progress("importing", dataset.numelements-oldnumelements+1); // +1 avoids zero-progress
369    for (i = oldnumelements; !error && i < dataset.numelements; i++) {
370        NA_Sequence *sequ = dataset.element+i;
371        int seqtyp, issame = 0;
372
373        seqtyp = sequ->elementtype;
374        if ((seqtyp == lotyp) || ((seqtyp == DNA) && (lotyp == RNA)) || ((seqtyp == RNA) && (lotyp == DNA))) {
375            issame = 1;
376        }
377        else {
378            aw_message(GBS_global_string("Warning: sequence type of species '%s' changed", sequ->short_name));
379        }
380
381        if (sequ->tmatrix) {
382            for (long j = 0; j < sequ->seqlen; j++) {
383                sequ->sequence[j] = (char)sequ->tmatrix[sequ->sequence[j]];
384            }
385            sequ->sequence[sequ->seqlen] = 0;
386        }
387
388        char *savename = GBS_string_2_key(sequ->short_name);
389
390        sequ->gb_species = 0;
391
392        const char *new_seq     = (const char *)sequ->sequence;
393        int         new_seq_len = sequ->seqlen;
394
395        gde_assert(new_seq[new_seq_len] == 0);
396        gde_assert((int)strlen(new_seq) == new_seq_len);
397
398        if (!issame) {          // save as extended
399            GBDATA *gb_extended = GBT_find_or_create_SAI(gb_main, savename);
400
401            if (!gb_extended) error = GB_await_error();
402            else {
403                sequ->gb_species = gb_extended;
404                GBDATA *gb_data  = GBT_add_data(gb_extended, ali_name, "data", GB_STRING);
405
406                if (!gb_data) error = GB_await_error();
407                else {
408                    error = write_sequence_autoinc_alisize(gb_data, maxalignlen, new_seq, new_seq_len);
409                    if (new_seq_len<maxalignlen) auto_format = true;
410                }
411            }
412        }
413        else {                  // save as sequence
414            GBDATA *gb_species_data     = GBT_get_species_data(gb_main);
415            if (!gb_species_data) error = GB_await_error();
416            else {
417                GBDATA *gb_species       = GBT_find_species_rel_species_data(gb_species_data, savename);
418                bool    fix_data_changes = false;
419
420                GB_push_my_security(gb_main);
421
422                if (gb_species) {   // new element that already exists !!!!
423                    enum ReplaceMode { REPLACE_SPEC = 0, REIMPORT_SEQ = 1, SKIP_IMPORT  = 2 } replace_mode;
424
425                    if (aligned_data) {
426                        replace_mode = REIMPORT_SEQ;
427                    }
428                    else {
429                        const char *question =
430                            GBS_global_string("You are (re-)importing a species '%s'.\n"
431                                              "That species already exists in your database!\n"
432                                              "\n"
433                                              "Possible actions:\n"
434                                              "\n"
435                                              "       - overwrite existing species (all fields)\n"
436                                              "       - overwrite the sequence (does not change other fields)\n"
437                                              "       - skip import of the species\n",
438                                              savename);
439
440                        replace_mode = (ReplaceMode)overwrite_question.get_answer("GDE_overwrite", question, "Overwrite species,Overwrite sequence only,Skip entry", "all", false);
441                    }
442
443                    switch (replace_mode) {
444                        case SKIP_IMPORT:
445                            gb_species = 0;
446                            break;
447                        case REPLACE_SPEC:
448                            error      = GB_delete(gb_species);
449                            gb_species = NULL;
450                            if (error) break;
451                            // fall-through
452                        case REIMPORT_SEQ:
453                            gb_species = GBT_find_or_create_species_rel_species_data(gb_species_data, savename);
454                            if (!gb_species) error = GB_await_error();
455                            break;
456                    }
457
458                    fix_data_changes = replace_mode == REIMPORT_SEQ;
459                }
460                else {
461                    if (aligned_data) {
462                        aw_message(GBS_global_string("Warning: new species '%s' has been created (unexpected; possible naming problems)", savename));
463                    }
464                    gb_species             = GBT_find_or_create_species_rel_species_data(gb_species_data, savename);
465                    if (!gb_species) error = GB_await_error();
466                }
467
468                if (gb_species) {
469                    gde_assert(!error);
470                    sequ->gb_species = gb_species;
471
472                    GBDATA *gb_data     = GBT_add_data(gb_species, ali_name, "data", GB_STRING); // does only add if not already existing
473                    if (!gb_data) error = GB_await_error();
474                    else {
475                        GBDATA *gb_old_data   = GBT_find_sequence(gb_species, ali_name);
476                        bool    writeSequence = true;
477                        if (gb_old_data) {          // we already have data -> compare checksums
478                            const char *old_seq = GB_read_char_pntr(gb_old_data);
479
480                            long old_checksum, new_checksum;
481                            bool calcStdChecksum = true;
482                            if (fix_data_changes) {
483                                char *new_seq_fixed = fix_aligned_data(old_seq, new_seq, dataset.alignment_type);  // apply some fixes to (realigned) data
484
485                                switch (dataset.alignment_type) {
486                                    case GB_AT_DNA:
487                                    case GB_AT_RNA: {
488                                        char *old_TU = GBS_string_eval(old_seq,       ":T=U:t=u", NULL);
489                                        char *new_TU = GBS_string_eval(new_seq_fixed, ":T=U:t=u", NULL);
490
491                                        old_checksum = GBS_checksum(old_TU, 1, "-.");
492                                        new_checksum = GBS_checksum(new_TU, 1, "-.");
493
494                                        free(new_TU);
495                                        free(old_TU);
496                                        break;
497                                    }
498                                    case GB_AT_AA:
499                                    case GB_AT_UNKNOWN:
500                                        old_checksum = GBS_checksum(old_seq,       1, "-.");
501                                        new_checksum = GBS_checksum(new_seq_fixed, 1, "-.");
502                                        break;
503                                }
504
505                                if (new_checksum == old_checksum) { // fix succeeded
506                                    free(sequ->sequence);
507                                    sequ->sequence  = (NA_Base*)new_seq_fixed;
508                                    new_seq         = new_seq_fixed;
509                                    calcStdChecksum = false;
510                                }
511                                else {
512                                    fprintf(stderr, "Checksum changed for '%s':\nold='%s'\nfix='%s' (failed)\nnew='%s'\n", savename, old_seq, new_seq_fixed, new_seq);
513                                    free(new_seq_fixed);
514                                }
515                            }
516                            if (calcStdChecksum) {
517                                old_checksum = GBS_checksum(old_seq, 1, "-.");
518                                new_checksum = GBS_checksum(new_seq, 1, "-.");
519                            }
520
521                            if (old_checksum != new_checksum) {
522                                if (!fix_data_changes) { // already dumped above
523                                    fprintf(stderr, "Checksum changed for '%s':\nold='%s'\nnew='%s'\n", savename, old_seq, new_seq);
524                                }
525
526                                char *question = GBS_global_string_copy("Warning: Sequence checksum of '%s' has changed!\n"
527                                                                        "This should NOT happen if you aligned sequences!\n"
528                                                                        "(see console for changes to sequence)", savename);
529
530                                const char *questionID = aligned_data ? "GDE_accept_aligner_seqchange" : "GDE_accept_seqchange";
531
532                                enum ChangeMode {
533                                    ACCEPT_CHANGE = 0,
534                                    REJECT_CHANGE = 1,
535                                } change_mode = (ChangeMode)checksum_change_question.get_answer(questionID, question, "Accept change,Reject", "all", false);
536
537                                if (change_mode == REJECT_CHANGE) writeSequence = false;
538
539                                aw_message(GBS_global_string("Warning: Sequence checksum for '%s' has changed (%s)",
540                                                             savename, writeSequence ? "accepted" : "rejected"));
541                                free(question);
542                            }
543                        }
544                        if (writeSequence) {
545                            error = write_sequence_autoinc_alisize(gb_data, maxalignlen, new_seq, new_seq_len);
546                            if (new_seq_len<maxalignlen) auto_format = true;
547                        }
548                    }
549                }
550                GB_pop_my_security(gb_main);
551            }
552        }
553        free(savename);
554        progress.inc_and_check_user_abort(error);
555    }
556
557    if (!auto_format) auto_format = oldalignlen != maxalignlen;
558
559    if (auto_format) {
560        if (db_access.format_ali) {
561            GB_push_my_security(gb_main);
562            error = db_access.format_ali(gb_main, ali_name);
563            GB_pop_my_security(gb_main);
564        }
565    }
566
567    progress.done();
568
569    GB_end_transaction_show_error(db_access.gb_main, error, aw_message);
570}
571
572static char *preCreateTempfile(const char *name) {
573    // creates a tempfile and returns heapcopy of fullpath
574    // exits in case of error
575    char *fullname = GB_create_tempfile(name);
576
577    if (!fullname) aw_message(GBS_global_string("[ARB_GDE]: %s", GB_await_error()));
578    return fullname;
579}
580
581void GDE_startaction_cb(AW_window *aw, GmenuItem *gmenuitem, AW_CL /*cd*/) {
582    gde_assert(!GB_have_error());
583
584    AW_root   *aw_root      = aw->get_root();
585    GmenuItem *current_item = gmenuitem;
586
587    GapCompression compress = static_cast<GapCompression>(aw_root->awar(AWAR_GDE_COMPRESSION)->read_int());
588    arb_progress   progress(current_item->label);
589    NA_Alignment   DataSet(db_access.gb_main);
590    int            stop     = 0;
591
592    if (current_item->numinputs>0) {
593        TypeInfo typeinfo = UNKNOWN_TYPEINFO;
594        {
595            for (int j=0; j<current_item->numinputs; j++) {
596                if (j == 0) { typeinfo = current_item->input[j].typeinfo; }
597                else if (current_item->input[j].typeinfo != typeinfo) {
598                    aw_message("'intyped' must be same for all inputs (config error in GDE menu file)");
599                    stop = 1;
600                }
601            }
602        }
603        gde_assert(typeinfo != UNKNOWN_TYPEINFO);
604
605        if (!stop) {
606            AP_filter *filter2 = awt_get_filter(agde_filter);
607            gde_assert(gmenuitem->seqtype != '-'); // inputs w/o seqtype? impossible!
608            {
609                GB_ERROR error = awt_invalid_filter(filter2);
610                if (error) {
611                    aw_message(error);
612                    stop = 1;
613                }
614            }
615
616            if (!stop) {
617                GB_transaction ta(DataSet.gb_main);
618                progress.subtitle("reading database");
619
620                long cutoff_stop_codon = aw_root->awar(AWAR_GDE_CUTOFF_STOPCODON)->read_int();
621                bool marked            = (aw_root->awar(AWAR_GDE_SPECIES)->read_int() != 0);
622
623                if (db_access.get_sequences) {
624                    stop = ReadArbdb2(DataSet, filter2, compress, cutoff_stop_codon, typeinfo);
625                }
626                else {
627                    stop = ReadArbdb(DataSet, marked, filter2, compress, cutoff_stop_codon, typeinfo);
628                }
629            }
630            delete filter2;
631        }
632
633        if (!stop && DataSet.numelements==0) {
634            aw_message("no sequences selected");
635            stop = 1;
636        }
637    }
638
639    if (!stop) {
640        int select_mode = (current_item->numinputs>0) ? ALL : NONE;
641        int pid         = getpid();
642
643        static int fileindx = 0;
644        for (int j=0; j<current_item->numinputs; j++) {
645            GfileFormat& gfile = current_item->input[j];
646
647            char buffer[GBUFSIZ];
648            sprintf(buffer, "gde%d_%d", pid, fileindx++);
649            gfile.name = preCreateTempfile(buffer);
650
651            switch (gfile.format) {
652                case GENBANK: WriteGen    (DataSet, gfile.name, select_mode); break;
653                case NA_FLAT: WriteNA_Flat(DataSet, gfile.name, select_mode); break;
654                case GDE:     WriteGDE    (DataSet, gfile.name, select_mode); break;
655                default: break;
656            }
657        }
658
659        for (int j=0; j<current_item->numoutputs; j++) {
660            char buffer[GBUFSIZ];
661            sprintf(buffer, "gde%d_%d", pid, fileindx++);
662            current_item->output[j].name = preCreateTempfile(buffer);
663        }
664
665        // Create the command line for external the function call
666        char *Action = strdup(current_item->method);
667
668        while (1) {
669            char *oldAction = strdup(Action);
670
671            for (int j=0; j<current_item->numargs; j++) Action = ReplaceArgs(aw_root, Action, gmenuitem, j);
672            bool changed = strcmp(oldAction, Action) != 0;
673            free(oldAction);
674
675            if (!changed) break;
676        }
677
678        for(int j=0; j<current_item->numinputs;  j++) Action = ReplaceFile(Action, current_item->input[j]);
679        for(int j=0; j<current_item->numoutputs; j++) Action = ReplaceFile(Action, current_item->output[j]);
680
681        if (Find(Action, "$FILTER") == true) {
682            char *filter_name = AWT_get_combined_filter_name(aw_root, "gde");
683            Action            = ReplaceString(Action, "$FILTER", filter_name);
684            free(filter_name);
685        }
686
687        // call and go...
688        progress.subtitle("calling external program");
689        aw_message_if(GBK_system(Action));
690        free(Action);
691
692        size_t oldnumelements = DataSet.numelements;
693
694        for (int j=0; j<current_item->numoutputs; j++) {
695            switch (current_item->output[j].format) {
696                case GENBANK:
697                case NA_FLAT:
698                case GDE:
699                    LoadData(current_item->output[j].name, DataSet);
700                    break;
701                default:
702                    gde_assert(0);
703                    break;
704            }
705        }
706        for (int j=0; j<current_item->numoutputs; j++) {
707            if (!current_item->output[j].save) {
708                unlink(current_item->output[j].name);
709            }
710        }
711
712        for (int j=0; j<current_item->numinputs; j++) {
713            if (!current_item->input[j].save) {
714                unlink(current_item->input[j].name);
715            }
716        }
717
718        export_to_DB(DataSet, oldnumelements, current_item->aligned);
719    }
720
721    gde_assert(!GB_have_error());
722}
723
724// --------------------------------------------------------------------------------
725
726#ifdef UNIT_TESTS
727#ifndef TEST_UNIT_H
728#include <test_unit.h>
729#endif
730
731static arb_test::match_expectation fixed_as(GB_alignment_type ali_type, const char *old, const char *expected_fix, const char *aligned) {
732    using namespace    arb_test;
733    char              *fixed = fix_aligned_data(old, aligned, ali_type);
734    match_expectation  e     = that(fixed).is_equal_to(expected_fix);
735    free(fixed);
736    return e;
737}
738
739#define TEST_FIX_ALIGNED(t,o,f,a)             TEST_EXPECTATION(fixed_as(t,o,f,a))
740#define TEST_FIX_ALIGNED__BROKEN(t,o,fw,fg,a) TEST_EXPECTATION__BROKEN(fixed_as(t,o,fw,a), fixed_as(t,o,fg,a))
741
742void TEST_fix_aligned_data() {
743    TEST_FIX_ALIGNED(GB_AT_RNA,
744                     "...A---CG..G--U.....", // old
745                     "..AC--G..GU...",       // fixed: gaps corrected; T->U
746                     "--AC--G--GT---");      // aligned
747
748    TEST_FIX_ALIGNED(GB_AT_RNA,
749                     "A---CG..G--U",         // old (no gaps at border)
750                     "--AC--G..GU---",       // fixed: gaps corrected; T->U
751                     "--AC--G--GT---");      // aligned
752
753    TEST_FIX_ALIGNED(GB_AT_RNA,
754                     "...A---CG..G--U.....", // old
755                     "AC--G..GU",            // fixed: gaps corrected; T->U
756                     "AC--G--GT");           // aligned (no gaps at border)
757
758    TEST_FIX_ALIGNED(GB_AT_RNA,
759                     "A---CG..G--U", // old
760                     "AC-----GT",    // not fixed
761                     "AC-----GT");   // aligned (bases changed!)
762
763    TEST_FIX_ALIGNED(GB_AT_DNA,
764                     "A---cTUu..G--t", // old
765                     "AcT--Tt..Gt",    // fixed: case restored; U's convert to T's
766                     "ACT--UT--GU");   // aligned
767
768    TEST_FIX_ALIGNED(GB_AT_RNA,
769                     "A---cTUu..G--t", // old
770                     "AcU--Uu..Gu",    // fixed: case restored; T's convert to U's
771                     "ACT--UT--GU");   // aligned
772}
773
774#endif // UNIT_TESTS
775
776// --------------------------------------------------------------------------------
Note: See TracBrowser for help on using the repository browser.