root/trunk/ARB_GDE/GDE_event.cxx

Revision 8646, 22.1 KB (checked in by westram, 5 weeks ago)
  • use results from system calls
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
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
17using namespace std;
18
19#define DEFAULT_COLOR 8
20extern adfiltercbstruct *agde_filtercd;
21
22/*
23  ReplaceArgs():
24  Replace all command line arguments with the appropriate values
25  stored for the chosen menu item.
26
27  Copyright (c) 1989-1990, University of Illinois board of trustees.  All
28  rights reserved.  Written by Steven Smith at the Center for Prokaryote Genome
29  Analysis.  Design and implementation guidance by Dr. Gary Olsen and Dr.
30  Carl Woese.
31
32  Copyright (c) 1990,1991,1992 Steven Smith at the Harvard Genome Laboratory.
33  All rights reserved.
34
35*/
36
37
38static char *ReplaceArgs(AW_root *awr, char *Action, GmenuItem *gmenuitem, int number)
39{
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 three
44     *  parts, a label, a method, and a value.  The method never changes, and
45     *  is used to represent '-flag's for a given function.  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.  All symbols without the '$' will
49     *  be replaced by their argmethod.  There is currently no way to do a label
50     *  replacement, as the label is considered to be for use in the dialog
51     *  box only.  An example command line replacement would be:
52     *
53     *       itemmethod=>        "lpr arg1 $arg1 $arg2"
54     *
55     *       arglabel arg1=>     "To printer?"
56     *       argmethod arg1=>    "-P"
57     *       argvalue arg1=>     "lw"
58     *
59     *       arglabel arg2=>     "File name?"
60     *       argvalue arg2=>     "foobar"
61     *       argmethod arg2=>    ""
62     *
63     *   final command line:
64     *
65     *       lpr -P lw foobar
66     *
67     *   At this point, the chooser dialog type only supports the arglabel and
68     *   argmethod field.  So if an argument is of type chooser, and
69     *   its symbol is "this", then "$this" has no real meaning in the
70     *   itemmethod definition.  Its format in the .GDEmenu file is slighty
71     *   different as well.  A choice from a chooser field looks like:
72     *
73     *       argchoice:Argument_label:Argument_method
74     *
75     *
76     */
77    const char *symbol=0;
78    char *method=0;
79    char *textvalue=0;
80    char *temp;
81    int i, newlen, type;
82    symbol = gmenuitem->arg[number].symbol;
83    type = gmenuitem->arg[number].type;
84    if ((type == SLIDER)) {
85        char *awarname = GDE_makeawarname(gmenuitem, number);
86        textvalue      = awr->awar(awarname)->read_as_string();
87        free(awarname);
88    }
89    else if (type == FILE_SELECTOR) {
90        char *awar_base = GDE_maketmpawarname(gmenuitem, number);
91        textvalue  = AW_get_selected_fullname(awr, awar_base);
92        free(awar_base);
93    }
94    else if ((type == CHOOSER) ||
95             (type == CHOICE_TREE) ||
96             (type == CHOICE_SAI) ||
97            (type == CHOICE_MENU) ||
98            (type == CHOICE_LIST) ||
99            (type == CHOICE_WEIGHTS) ||
100            (type == TEXTFIELD))
101    {
102        char *awarname=GDE_makeawarname(gmenuitem, number);
103        method=awr->awar(awarname)->read_string();
104        textvalue=awr->awar(awarname)->read_string();
105    }
106
107    if (textvalue == NULL)  textvalue=(char *)calloc(1, sizeof(char));
108    if (method == NULL)     method=(char *)calloc(1, sizeof(char));
109    if (symbol == NULL)     symbol="";
110
111    set<string>warned_about;
112    int conversion_warning        = 0;
113    int j                         = 0;
114
115    for (; (i=Find2(Action+j, symbol)) != -1;)
116    {
117        i += j;
118        ++j;
119        if (i>0 && Action[i-1] == '$')
120        {
121            newlen = strlen(Action)-strlen(symbol)
122                +strlen(textvalue);
123            temp = (char *)calloc(newlen, 1);
124            if (temp == NULL)
125                Error("ReplaceArgs():Error in calloc");
126            strncat(temp, Action, i-1);
127            strncat(temp, textvalue, strlen(textvalue));
128            strcat(temp, &(Action[i+strlen(symbol)]));
129            freeset(Action, temp);
130        }
131        else {
132            if (warned_about.find(symbol) == warned_about.end()) {
133                fprintf(stderr,
134                        "old arb version converted '%s' to '%s' (now only '$%s' is converted)\n",
135                        symbol, textvalue, symbol);
136                conversion_warning++;
137                warned_about.insert(symbol);
138            }
139        }
140    }
141
142    if (conversion_warning) {
143        fprintf(stderr,
144                "Conversion warnings occurred in Action:\n'%s'\n",
145                Action);
146    }
147
148    free(textvalue);
149    free(method);
150    return (Action);
151}
152
153
154
155static long LMAX(long a, long b)
156{
157    if (a>b) return a;
158    return b;
159}
160
161static void GDE_free(void **p) {
162    freenull(*p);
163}
164
165static char *ReplaceFile(char *Action, GfileFormat file)
166{
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    {
174        newlen = strlen(Action)-strlen(symbol) + strlen(method)+1;
175        temp = (char *)calloc(newlen, 1);
176        if (temp == NULL)
177            Error("ReplaceFile():Error in calloc");
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        if (temp == NULL)
201            Error("ReplaceFile():Error in calloc");
202        strncat(temp, Action, i);
203        strncat(temp, method, strlen(method));
204        strcat(temp, &(Action[i+strlen(symbol)]));
205        freeset(Action, temp);
206    }
207    return (Action);
208}
209
210
211static void GDE_freesequ(NA_Sequence *sequ) {
212    if (sequ) {
213        GDE_free((void**)&sequ->comments);
214        GDE_free((void**)&sequ->cmask);
215        GDE_free((void**)&sequ->baggage);
216        GDE_free((void**)&sequ->sequence);
217    }
218}
219
220static void GDE_freeali(NA_Alignment *dataset) {
221    if (dataset) {
222        GDE_free((void**)&dataset->id);
223        GDE_free((void**)&dataset->description);
224        GDE_free((void**)&dataset->authority);
225        GDE_free((void**)&dataset->cmask);
226        GDE_free((void**)&dataset->selection_mask);
227        GDE_free((void**)&dataset->alignment_name);
228
229        for (unsigned long i=0; i<dataset->numelements; i++) {
230            GDE_freesequ(dataset->element+i);
231        }
232    }
233}
234
235static void GDE_export(NA_Alignment *dataset, char *align, long oldnumelements) {
236    GBDATA   *gb_main = db_access.gb_main;
237    GB_ERROR  error   = GB_begin_transaction(gb_main);
238
239    long maxalignlen    = GBT_get_alignment_len(gb_main, align);
240    long isdefaultalign = 0;
241
242    if (maxalignlen <= 0 && !error) {
243        GB_clear_error(); // clear "alignment not found" error
244   
245        align             = GBT_get_default_alignment(gb_main);
246        if (!align) error = GB_await_error();
247        else {
248            isdefaultalign = 1;
249            maxalignlen    = GBT_get_alignment_len(gb_main, align);
250        }
251    }
252
253    long lotyp = 0;
254    if (!error) {
255        GB_alignment_type at = GBT_get_alignment_type(gb_main, align);
256
257        switch (at) {
258            case GB_AT_DNA:     lotyp = DNA;     break;
259            case GB_AT_RNA:     lotyp = RNA;     break;
260            case GB_AT_AA:      lotyp = PROTEIN; break;
261            case GB_AT_UNKNOWN: lotyp = DNA;     break;
262        }
263    }
264
265    unsigned long i;
266
267    AW_repeated_question overwrite_question;
268    AW_repeated_question checksum_change_question;
269   
270    arb_progress progress("importing", dataset->numelements-oldnumelements+1); // +1 avoids zero-progress
271    for (i = oldnumelements; !error && i < dataset->numelements; i++) {
272        NA_Sequence *sequ = dataset->element+i;
273        int seqtyp, issame = 0;
274
275        seqtyp = sequ->elementtype;
276        if ((seqtyp == lotyp) || ((seqtyp == DNA) && (lotyp == RNA)) || ((seqtyp == RNA) && (lotyp == DNA))) {
277            issame = 1;
278        }
279        else {
280            aw_message(GBS_global_string("Warning: sequence type of species '%s' changed", sequ->short_name));
281        }
282
283        if (sequ->tmatrix) {
284            for (long j = 0; j < sequ->seqlen; j++) {
285                sequ->sequence[j] = (char)sequ->tmatrix[sequ->sequence[j]];
286            }
287            sequ->sequence[sequ->seqlen] = 0;
288        }
289
290        char *savename = GBS_string_2_key(sequ->short_name);
291
292        sequ->gb_species = 0;
293
294        const char *new_seq = (const char *)sequ->sequence;
295        gde_assert(new_seq[sequ->seqlen] == 0);
296        gde_assert((int)strlen(new_seq) == sequ->seqlen);
297
298        if (!issame) {          // save as extended
299            GBDATA *gb_extended = GBT_find_or_create_SAI(db_access.gb_main, savename);
300
301            if (!gb_extended) error = GB_await_error();
302            else {
303                sequ->gb_species = gb_extended;
304                GBDATA *gb_data  = GBT_add_data(gb_extended, align, "data", GB_STRING);
305
306                if (!gb_data) error = GB_await_error();
307                else error          = GBT_write_sequence(gb_data, align, maxalignlen, new_seq);
308            }
309        }
310        else {                  // save as sequence
311            GBDATA *gb_species_data     = GBT_get_species_data(db_access.gb_main);
312            if (!gb_species_data) error = GB_await_error();
313            else {
314                GBDATA *gb_species = GBT_find_species_rel_species_data(gb_species_data, savename);
315
316                GB_push_my_security(db_access.gb_main);
317
318                if (gb_species) {   // new element that already exists !!!!
319                    const char *question =
320                        GBS_global_string("You are (re-)importing a species '%s'.\n"
321                                          "That species already exists in your database!\n"
322                                          "\n"
323                                          "Possible actions:\n"
324                                          "\n"
325                                          "       - overwrite existing species (all fields)\n"
326                                          "       - overwrite the sequence (does not change other fields)\n"
327                                          "       - skip import of the species\n"
328                                          "\n"
329                                          "Note: After aligning it's recommended to choose 'overwrite sequence'.",
330                                          savename);
331
332
333                    enum ReplaceMode { REPLACE_SPEC = 0, REIMPORT_SEQ = 1, SKIP_IMPORT  = 2, }
334                    replace_mode = (ReplaceMode)overwrite_question.get_answer("GDE_overwrite", question, "Overwrite species,Overwrite sequence only,Skip entry", "all", false);
335
336                    switch (replace_mode) {
337                        case SKIP_IMPORT:
338                            gb_species = 0;
339                            break;
340                        case REPLACE_SPEC:
341                            error      = GB_delete(gb_species);
342                            gb_species = NULL;
343                            if (error) break;
344                            // fall-through
345                        case REIMPORT_SEQ:
346                            gb_species = GBT_find_or_create_species_rel_species_data(gb_species_data, savename);
347                            if (!gb_species) error = GB_await_error();
348                            break;
349                    }
350                }
351                else {
352                    gb_species = GBT_find_or_create_species_rel_species_data(gb_species_data, savename);
353                    if (!gb_species) error = GB_await_error();
354                }
355
356                if (gb_species) {
357                    gde_assert(!error);
358                    sequ->gb_species = gb_species;
359
360                    GBDATA *gb_data     = GBT_add_data(gb_species, align, "data", GB_STRING); // does only add if not already existing
361                    if (!gb_data) error = GB_await_error();
362                    else {
363                        GBDATA *gb_old_data   = GBT_read_sequence(gb_species, align);
364                        bool    writeSequence = true;
365                        if (gb_old_data) {          // we already have data -> compare checksums
366                            const char *old_seq      = GB_read_char_pntr(gb_old_data);
367                            long        old_checksum = GBS_checksum(old_seq, 1, "-.");
368                            long        new_checksum = GBS_checksum(new_seq, 1, "-.");
369
370                            if (old_checksum != new_checksum) {
371                                const char *question = GBS_global_string("Warning: Sequence checksum of '%s' has changed\n", savename);
372                                enum ChangeMode {
373                                    ACCEPT_CHANGE = 0,
374                                    REJECT_CHANGE = 1,
375                                } change_mode = (ChangeMode)checksum_change_question.get_answer("GDE_accept", question, "Accept change,Reject", "all", false);
376                               
377                                if (change_mode == REJECT_CHANGE) writeSequence = false;
378
379                                aw_message(GBS_global_string("Warning: Sequence checksum for '%s' has changed (%s)",
380                                                             savename, writeSequence ? "accepted" : "rejected"));
381                            }
382                        }
383                        if (writeSequence) {
384                            error = GBT_write_sequence(gb_data, align, maxalignlen, new_seq);
385                        }
386                    }
387                }
388                GB_pop_my_security(db_access.gb_main);
389            }
390        }
391        free(savename);
392        progress.inc_and_check_user_abort(error);
393    }
394
395    // colormasks
396    for (i = 0; !error && i < dataset->numelements; i++) {
397        NA_Sequence *sequ = &(dataset->element[i]);
398
399        if (sequ->cmask) {
400            maxalignlen     = LMAX(maxalignlen, sequ->seqlen);
401            char *resstring = (char *)calloc((unsigned int)maxalignlen + 1, sizeof(char));
402            char *dummy     = resstring;
403
404            for (long j = 0; j < maxalignlen - sequ->seqlen; j++) *resstring++ = DEFAULT_COLOR;
405            for (long k = 0; k < sequ->seqlen; k++)               *resstring++ = (char)sequ->cmask[i];
406            *resstring = '\0';
407
408            GBDATA *gb_ali     = GB_search(sequ->gb_species, align, GB_CREATE_CONTAINER);
409            if (!gb_ali) error = GB_await_error();
410            else {
411                GBDATA *gb_color     = GB_search(gb_ali, "colmask", GB_BYTES);
412                if (!gb_color) error = GB_await_error();
413                else    error        = GB_write_bytes(gb_color, dummy, maxalignlen);
414            }
415            free(dummy);
416        }
417    }
418
419    if (!error && dataset->cmask) {
420        maxalignlen     = LMAX(maxalignlen, dataset->cmask_len);
421        char *resstring = (char *)calloc((unsigned int)maxalignlen + 1, sizeof(char));
422        char *dummy     = resstring;
423        long  k;
424
425        for (k = 0; k < maxalignlen - dataset->cmask_len; k++) *resstring++ = DEFAULT_COLOR;
426        for (k = 0; k < dataset->cmask_len; k++)               *resstring++ = (char)dataset->cmask[k];
427        *resstring = '\0';
428
429        GBDATA *gb_extended     = GBT_find_or_create_SAI(db_access.gb_main, "COLMASK");
430        if (!gb_extended) error = GB_await_error();
431        else {
432            GBDATA *gb_color     = GBT_add_data(gb_extended, align, "colmask", GB_BYTES);
433            if (!gb_color) error = GB_await_error();
434            else    error        = GB_write_bytes(gb_color, dummy, maxalignlen);
435        }
436
437        free(dummy);
438    }
439
440    progress.done();
441
442    GB_end_transaction_show_error(db_access.gb_main, error, aw_message);
443    if (isdefaultalign) free(align);
444}
445
446static char *preCreateTempfile(const char *name) {
447    // creates a tempfile and returns heapcopy of fullpath
448    // exits in case of error
449    char *fullname = GB_create_tempfile(name);
450
451    if (!fullname) Error(GBS_global_string("preCreateTempfile: %s", GB_await_error())); // exits
452    return fullname;
453}
454
455void GDE_startaction_cb(AW_window *aw, GmenuItem *gmenuitem, AW_CL /*cd*/) {
456    long oldnumelements=0;
457    AW_root *aw_root=aw->get_root();
458
459    GapCompression  compress          = static_cast<GapCompression>(aw_root->awar(AWAR_GDE_COMPRESSION)->read_int());
460    AP_filter      *filter2           = awt_get_filter(agde_filtercd);
461    char           *filter_name       = 0; // aw_root->awar(AWAR_GDE_FILTER_NAME)->read_string()
462    char           *alignment_name    = strdup("ali_unknown");
463    bool            marked            = (aw_root->awar(AWAR_GDE_SPECIES)->read_int() != 0);
464    long            cutoff_stop_codon = aw_root->awar(AWAR_GDE_CUTOFF_STOPCODON)->read_int();
465    GmenuItem      *current_item      = gmenuitem;
466    arb_progress    progress(current_item->label);
467
468    int   j;
469    bool  flag;
470    char *Action, buffer[GBUFSIZ];
471
472    static int fileindx    = 0;
473    int        select_mode = 0;
474    int        stop        = 0;
475
476    if (current_item->numinputs>0) {
477        DataSet->gb_main = db_access.gb_main;
478        GB_begin_transaction(DataSet->gb_main);
479        freeset(DataSet->alignment_name, GBT_get_default_alignment(DataSet->gb_main));
480        freedup(alignment_name, DataSet->alignment_name);
481
482        progress.subtitle("reading database");
483        if (db_access.get_sequences) {
484            stop = ReadArbdb2(DataSet, filter2, compress, cutoff_stop_codon);
485        }
486        else {
487            stop = ReadArbdb(DataSet, marked, filter2, compress, cutoff_stop_codon);
488        }
489        GB_commit_transaction(DataSet->gb_main);
490
491        if (!stop && DataSet->numelements==0) {
492            aw_message("no sequences selected");
493            stop = 1;
494        }
495    }
496
497    if (!stop) {
498        flag = false;
499        for (j=0; j<current_item->numinputs; j++) {
500            if (current_item->input[j].format != STATUS_FILE) {
501                flag = true;
502            }
503        }
504        if (flag && DataSet) select_mode = ALL;
505
506        int pid = getpid();
507
508        for (j=0; j<current_item->numinputs; j++) {
509            GfileFormat& gfile = current_item->input[j];
510
511            sprintf(buffer, "gde%d_%d", pid, fileindx++);
512            gfile.name = preCreateTempfile(buffer);
513
514            switch (gfile.format) {
515                case COLORMASK:   WriteCMask  (DataSet, gfile.name, select_mode, gfile.maskable); break;
516                case GENBANK:     WriteGen    (DataSet, gfile.name, select_mode, gfile.maskable); break;
517                case NA_FLAT:     WriteNA_Flat(DataSet, gfile.name, select_mode, gfile.maskable); break;
518                case STATUS_FILE: WriteStatus (DataSet, gfile.name);                 break;
519                case GDE:         WriteGDE    (DataSet, gfile.name, select_mode, gfile.maskable); break;
520                default: break;
521            }
522        }
523
524        for (j=0; j<current_item->numoutputs; j++) {
525            sprintf(buffer, "gde%d_%d", pid, fileindx++);
526            current_item->output[j].name = preCreateTempfile(buffer);
527        }
528
529        // Create the command line for external the function call
530        Action = (char*)strdup(current_item->method);
531        if (Action == NULL) Error("DO(): Error in duplicating method string");
532
533        while (1) {
534            char *oldAction = strdup(Action);
535
536            for (j=0; j<current_item->numargs; j++) Action = ReplaceArgs(aw_root, Action, gmenuitem, j);
537            bool changed = strcmp(oldAction, Action) != 0;
538            free(oldAction);
539
540            if (!changed) break;
541        }
542
543        for (j=0; j<current_item->numinputs; j++) Action = ReplaceFile(Action, current_item->input[j]);
544        for (j=0; j<current_item->numoutputs; j++) Action = ReplaceFile(Action, current_item->output[j]);
545
546        filter_name = AWT_get_combined_filter_name(aw_root, "gde");
547        Action = ReplaceString(Action, "$FILTER", filter_name);
548
549        // call and go...
550        progress.subtitle("calling external program");
551        aw_message_if(GBK_system(Action));
552        free(Action);
553
554        oldnumelements=DataSet->numelements;
555
556        BlockInput = false;
557
558        for (j=0; j<current_item->numoutputs; j++)
559        {
560            if (current_item->output[j].overwrite)
561            {
562                if (current_item->output[j].format == GDE)
563                    OVERWRITE = true;
564                else
565                    Warning("Overwrite mode only available for GDE format");
566            }
567            switch (current_item->output[j].format)
568            {
569                /* The LoadData routine must be reworked so that
570                 * OpenFileName uses it, and so I can remove the
571                 * major kluge in OpenFileName().
572                 */
573                case GENBANK:
574                case NA_FLAT:
575                case GDE:
576                    LoadData(current_item->output[j].name);
577                    break;
578                case COLORMASK:
579                    ReadCMask(current_item->output[j].name);
580                    break;
581                default:
582                    break;
583            }
584            OVERWRITE = false;
585        }
586        for (j=0; j<current_item->numoutputs; j++)
587        {
588            if (!current_item->output[j].save)
589            {
590                unlink(current_item->output[j].name);
591            }
592        }
593
594        for (j=0; j<current_item->numinputs; j++)
595        {
596            if (!current_item->input[j].save)
597            {
598                unlink(current_item->input[j].name);
599            }
600        }
601
602        GDE_export(DataSet, alignment_name, oldnumelements);
603    }
604
605    free(alignment_name);
606    delete filter2;
607    free(filter_name);
608
609    GDE_freeali(DataSet);
610    freeset(DataSet, (NA_Alignment *)Calloc(1, sizeof(NA_Alignment)));
611    DataSet->rel_offset = 0;
612}
Note: See TracBrowser for help on using the browser.