source: tags/ms_r18q1/ARB_GDE/GDE_event.cxx

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