source: tags/ms_r18q1/AWTI/AWTI_import.cxx

Last change on this file was 16961, checked in by westram, 6 years ago
  • partial merge from 'fix' into 'trunk'
    • refactored AW_device text output
      • reduces calls to strlen (using SizedCstr)
      • eliminated/modernized several parameters/functions (esp. in TextOverlayCallbacks)
  • adds: log:branches/fix@16939:16960
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 54.8 KB
Line 
1// ============================================================= //
2//                                                               //
3//   File      : AWTI_import.cxx                                 //
4//   Purpose   :                                                 //
5//                                                               //
6//   Institute of Microbiology (Technical University Munich)     //
7//   http://www.arb-home.de/                                     //
8//                                                               //
9// ============================================================= //
10
11#include "awti_imp_local.hxx"
12
13#include <FileWatch.h>
14#include <seqio.hxx>
15#include <item_sel_list.h>
16#include <awt.hxx>
17
18#include <aw_advice.hxx>
19#include <aw_file.hxx>
20#include <AW_rename.hxx>
21#include <aw_msg.hxx>
22#include <aw_question.hxx>
23
24#include <GenomeImport.h>
25#include <GEN.hxx>
26#include <adGene.h>
27#include <arb_progress.h>
28#include <arb_strbuf.h>
29#include <arb_str.h>
30#include <macros.hxx>
31
32#include <climits>
33#include <unistd.h>
34#include <gb_aci.h>
35#include "awti_edit.hxx"
36
37using namespace std;
38using namespace SEQIO;
39
40#define MAX_COMMENT_LINES 2000
41
42
43inline const char *name_only(const char *fullpath) {
44    const char *lslash = strrchr(fullpath, '/');
45    return lslash ? lslash+1 : fullpath;
46}
47
48
49inline GB_ERROR not_in_match_error(const char *cmd) {
50    return GBS_global_string("Command '%s' may only appear after 'MATCH'", cmd);
51}
52
53inline bool wants_import_genome(AW_root *awr) { return awr->awar(AWAR_IMPORT_GENOM_DB)->read_int() == IMP_GENOME_FLATFILE; }
54
55static char *encode_escaped_chars(char *com) {
56    // Encodes the escape sequences "\\n", "\\t" and "\\0" to their corresponding characters
57    // Other occurrences of "\\" are removed.
58
59    char *result, *s, *d;
60    int   ch;
61
62    s = d = result = ARB_strdup(com);
63    while ((ch = *(s++))) {
64        switch (ch) {
65            case '\\':
66                ch = *(s++); if (!ch) { s--; break; };
67                switch (ch) {
68                    case 'n':   *(d++) = '\n'; break;
69                    case 't':   *(d++) = '\t'; break;
70                    case '0':   *(d++) = '\0'; break;
71                    default:    *(d++) = ch; break;
72                }
73                break;
74            default:
75                *(d++) = ch;
76        }
77    }
78    *d = 0;
79    return result;
80}
81
82static GB_ERROR read_import_format(const char *fullfile, import_format *ifo, bool *var_set, bool included) {
83    GB_ERROR  error = NULp;
84    FILE     *in    = fopen(fullfile, "rt");
85
86    import_match *m = ifo->match;
87
88    if (!in) {
89        const char *name = name_only(fullfile);
90
91        if (included) {
92            error = GB_export_IO_error("including", name);
93        }
94        else {
95            error = strchr(name, '*')
96                ? "Please use 'AUTO DETECT' or manually select an import format"
97                : GB_IO_error("loading import filter", name);
98        }
99    }
100    else {
101        char   *s1, *s2;
102        size_t  lineNumber    = 0;
103        bool    include_error = false;
104
105        while (!error && read_string_pair(in, s1, s2, lineNumber)) {
106
107#define GLOBAL_COMMAND(cmd) (!error && strcmp(s1, cmd) == 0)
108#define MATCH_COMMAND(cmd)  (GLOBAL_COMMAND(cmd) && (m || !(error = not_in_match_error(cmd))))
109
110            if (GLOBAL_COMMAND("MATCH")) {
111                m = new import_match;
112
113                m->defined_at = GBS_global_string_copy("%zi,%s", lineNumber, name_only(fullfile));
114                m->next       = ifo->match; // this concatenates the filters to the front -> the list is reversed below
115                ifo->match    = m;
116                m->match      = encode_escaped_chars(s2);
117                m->type       = GB_STRING;
118
119                if (ifo->autotag) m->mtag = ARB_strdup(ifo->autotag); // will be overwritten by TAG command
120            }
121            else if (MATCH_COMMAND("SRT"))         { reassign(m->srt, s2); }
122            else if (MATCH_COMMAND("ACI"))         { reassign(m->aci, s2); }
123            else if (MATCH_COMMAND("WRITE"))       { reassign(m->write, s2); }
124            else if (MATCH_COMMAND("WRITE_INT"))   { reassign(m->write, s2); m->type = GB_INT; }
125            else if (MATCH_COMMAND("WRITE_FLOAT")) { reassign(m->write, s2); m->type = GB_FLOAT; }
126            else if (MATCH_COMMAND("APPEND"))      { reassign(m->append, s2); }
127            else if (MATCH_COMMAND("SETVAR")) {
128                if (strlen(s2) != 1 || s2[0]<'a' || s2[0]>'z') {
129                    error = "Allowed variable names are a-z";
130                }
131                else {
132                    var_set[s2[0]-'a'] = true;
133                    reassign(m->setvar, s2);
134                }
135            }
136            else if (MATCH_COMMAND("TAG")) {
137                if (s2[0]) reassign(m->mtag, s2);
138                else error = "Empty TAG is not allowed";
139            }
140            else if (GLOBAL_COMMAND("AUTODETECT"))               { reassign(ifo->autodetect,    s2); }
141            else if (GLOBAL_COMMAND("SYSTEM"))                   { reassign(ifo->system,        s2); }
142            else if (GLOBAL_COMMAND("NEW_FORMAT"))               { reassign(ifo->new_format,    s2); ifo->new_format_lineno = lineNumber; }
143            else if (GLOBAL_COMMAND("BEGIN"))                    { reassign(ifo->begin,         s2); }
144            else if (GLOBAL_COMMAND("FILETAG"))                  { reassign(ifo->filetag,       s2); }
145            else if (GLOBAL_COMMAND("SEQUENCESRT"))              { reassign(ifo->sequencesrt,   s2); }
146            else if (GLOBAL_COMMAND("SEQUENCEACI"))              { reassign(ifo->sequenceaci,   s2); }
147            else if (GLOBAL_COMMAND("SEQUENCEEND"))              { reassign(ifo->sequenceend,   s2); }
148            else if (GLOBAL_COMMAND("END"))                      { reassign(ifo->end,           s2); } // @@@ has no effect -> silently ignore (no need to store)
149            else if (GLOBAL_COMMAND("AUTOTAG"))                  { reassign(ifo->autotag,       s2); }
150            else if (GLOBAL_COMMAND("SEQUENCESTART"))            { reassign(ifo->sequencestart, s2); ifo->read_this_sequence_line_too = 1; }
151            else if (GLOBAL_COMMAND("SEQUENCEAFTER"))            { reassign(ifo->sequencestart, s2); ifo->read_this_sequence_line_too = 0; }
152            else if (GLOBAL_COMMAND("KEYWIDTH"))                 { ifo->tab            = atoi(s2); }
153            else if (GLOBAL_COMMAND("SEQUENCECOLUMN"))           { ifo->sequencecolumn = atoi(s2); }
154            else if (GLOBAL_COMMAND("CREATE_ACC_FROM_SEQUENCE")) { ifo->autocreateacc  = 1; }
155            else if (GLOBAL_COMMAND("DONT_GEN_NAMES"))           { ifo->noautonames    = 1; }
156            else if (GLOBAL_COMMAND("DESCRIPTION"))              { appendTo(ifo->description, '\n', s2); }
157            else if (GLOBAL_COMMAND("INCLUDE")) {
158                char *dir         = AW_extract_directory(fullfile);
159                char *includeFile = GBS_global_string_copy("%s/%s", dir, s2);
160
161                error = read_import_format(includeFile, ifo, var_set, true);
162                if (error) include_error = true;
163
164                free(includeFile);
165                free(dir);
166            }
167            else {
168                bool ifnotset  = GLOBAL_COMMAND("IFNOTSET");
169                bool setglobal = GLOBAL_COMMAND("SETGLOBAL");
170
171                if (ifnotset || setglobal) {
172                    if (s2[0]<'a' || s2[0]>'z') {
173                        error = "Allowed variable names are a-z";
174                    }
175                    else {
176                        int off = 1;
177                        while (isblank(s2[off])) off++;
178                        if (!s2[off]) error = GBS_global_string("Expected two arguments in '%s'", s2);
179                        else {
180                            char        varname = s2[0];
181                            const char *arg2    = s2+off;
182
183                            if (ifnotset) {
184                                if (ifo->variable_errors.get(varname)) {
185                                    error = GBS_global_string("Redefinition of IFNOTSET %c", varname);
186                                }
187                                else {
188                                    ifo->variable_errors.set(varname, arg2);
189                                }
190                            }
191                            else {
192                                awti_assert(setglobal);
193                                ifo->global_variables.set(varname, arg2);
194                                var_set[varname-'a'] = true;
195                            }
196                        }
197                    }
198                }
199                else if (!error) {
200                    error = GBS_global_string("Unknown command '%s'", s1);
201                }
202            }
203
204            free(s1);
205            free(s2);
206        }
207
208        // check if required fields are defined
209        if (!error && !included) { // do not run checks for included part (allowed to be incomplete)
210            if (ifo->system || ifo->new_format) {
211                if      (!ifo->system)     error = "Missing command SYSTEM (needed with NEW_FORMAT)";
212                else if (!ifo->new_format) error = "Missing command NEW_FORMAT (needed with SYSTEM)";
213
214                if (!error && ifo->sequencestart) {
215                    error = "SEQUENCESTART/SEQUENCEAFTER cannot be used together with NEW_FORMAT";
216                }
217            }
218            else {
219                if (!ifo->sequencestart) {
220                    error = "neither SEQUENCESTART nor SEQUENCEAFTER specified (need one of them)";
221                }
222            }
223        }
224
225        if (error) {
226            error = GBS_global_string("%sin line %zi of %s '%s':\n%s",
227                                      include_error ? "included " : "",
228                                      lineNumber,
229                                      included ? "file" : "import format",
230                                      name_only(fullfile),
231                                      error);
232        }
233
234        fclose(in);
235
236#undef MATCH_COMMAND
237#undef GLOBAL_COMMAND
238    }
239
240    return error;
241}
242
243GB_ERROR ArbImporter::read_format(const char *file) {
244    char *fullfile = ARB_strdup(GB_path_in_ARBHOME(file));
245
246    delete ifo;
247    ifo = new import_format;
248
249    bool var_set[IFS_VARIABLES];
250    for (int i = 0; i<IFS_VARIABLES; i++) var_set[i] = false;
251
252    GB_ERROR error = read_import_format(fullfile, ifo, var_set, false);
253
254
255    for (int i = 0; i<IFS_VARIABLES && !error; i++) {
256        bool ifnotset = ifo->variable_errors.get(i+'a');
257        if (var_set[i]) {
258            bool isglobal = ifo->global_variables.get(i+'a');
259            if (!ifnotset && !isglobal) { // don't warn if variable is global
260                error = GBS_global_string("Warning: missing IFNOTSET for variable '%c'", 'a'+i);
261            }
262        }
263        else {
264            if (ifnotset) {
265                error = GBS_global_string("Warning: useless IFNOTSET for unused variable '%c'", 'a'+i);
266            }
267        }
268    }
269
270    // reverse order of match list (was appended backwards during creation)
271    if (ifo->match) ifo->match = ifo->match->reverse(NULp);
272
273    free(fullfile);
274
275    return error;
276}
277
278import_match::import_match() :
279    match(NULp),
280    aci(NULp),
281    srt(NULp),
282    mtag(NULp),
283    append(NULp),
284    write(NULp),
285    setvar(NULp),
286    type(GB_NONE),
287    defined_at(NULp),
288    next(NULp)
289{}
290
291import_match::~import_match() {
292    free(match);
293    free(aci);
294    free(srt);
295    free(mtag);
296    free(append);
297    free(write);
298    free(setvar);
299    free(defined_at);
300
301    delete next;
302}
303
304import_format::import_format() :
305    autodetect(NULp),
306    system(NULp),
307    new_format(NULp),
308    new_format_lineno(0),
309    tab(0),
310    description(NULp),
311    begin(NULp),
312    sequencestart(NULp),
313    read_this_sequence_line_too(0),
314    sequenceend(NULp),
315    sequencesrt(NULp),
316    sequenceaci(NULp),
317    filetag(NULp),
318    autotag(NULp),
319    sequencecolumn(0),
320    autocreateacc(0),
321    noautonames(0),
322    end(NULp),
323    b1(NULp),
324    b2(NULp),
325    match(NULp)
326{}
327
328import_format::~import_format() {
329    free(autodetect);
330    free(system);
331    free(new_format);
332    free(description);
333    free(begin);
334    free(sequencestart);
335    free(sequenceend);
336    free(sequencesrt);
337    free(sequenceaci);
338    free(filetag);
339    free(autotag);
340    free(end);
341    free(b1);
342    free(b2);
343
344    delete match;
345}
346
347
348static int cmp_ift(const void *p0, const void *p1, void *) {
349    return ARB_stricmp((const char *)p0, (const char *)p1);
350}
351
352inline bool is_hidden_file(const char *file) {
353    const char *name  = strrchr(file, '/');
354    name              = name ? name+1 : file;
355    return name[0]   == '.';
356}
357
358static void removeHiddenFiles(StrArray& files) {
359    for (int i = files.size()-1; i >= 0; --i) {
360        if (is_hidden_file(files[i])) {
361            files.remove(i);
362        }
363    }
364}
365
366void ArbImporter::detect_format(AW_root *root) {
367    StrArray files;
368    {
369        AW_awar       *awar_dirs = root->awar(AWAR_IMPORT_FORMATDIR);
370        ConstStrArray  dirs;
371        GBT_split_string(dirs, awar_dirs->read_char_pntr(), ":", true);
372        for (unsigned i = 0; i<dirs.size(); ++i) GBS_read_dir(files, dirs[i], "*.ift");
373        removeHiddenFiles(files);
374    }
375    files.sort(cmp_ift, NULp);
376
377    char     buffer[AWTI_IMPORT_CHECK_BUFFER_SIZE+10];
378    GB_ERROR error = NULp;
379
380    int matched       = -1;
381    int first         = -1;
382    int matched_count = 0;
383
384    AW_awar *awar_filter   = root->awar(AWAR_IMPORT_FORMATNAME);
385    char    *prev_selected = awar_filter->read_string();
386
387    // read start of (1st) file to import into 'buffer'
388    {
389        FILE *test = NULp;
390        {
391            char *f = root->awar(AWAR_IMPORT_FILENAME)->read_string();
392
393            if (f[0]) {
394                const char *com = GBS_global_string("cat %s 2>/dev/null", f);
395                test            = popen(com, "r");
396            }
397            free(f);
398            if (!test) error = "No input file specified -> cannot detect anything";
399        }
400        if (test) {
401            int size = fread(buffer, 1, AWTI_IMPORT_CHECK_BUFFER_SIZE, test);
402            pclose(test);
403            if (size>=0) buffer[size] = 0;
404        }
405        else {
406            buffer[0] = 0;
407        }
408    }
409
410    for (int idx = 0; files[idx] && !error; ++idx) {
411        const char *filtername = files[idx];
412        awar_filter->write_string(filtername);
413
414        GB_ERROR form_err = read_format(filtername);
415        if (form_err) {
416            aw_message(form_err);
417        }
418        else {
419            if (ifo->autodetect) {      // detectable
420                char *autodetect = encode_escaped_chars(ifo->autodetect);
421                if (GBS_string_matches(buffer, autodetect, GB_MIND_CASE)) {
422                    // format found!
423                    matched_count++;
424                    if (matched == -1) matched = idx; // remember first/next found format
425                    if (first == -1) first     = idx; // remember first found format
426
427                    if (strcmp(filtername, prev_selected) == 0) { // previously selected filter
428                        matched = -1; // select next (or first.. see below)
429                    }
430                }
431                free(autodetect);
432            }
433        }
434
435        delete ifo; ifo = NULp;
436    }
437
438    const char *select = NULp;
439    if (!error) {
440        switch (matched_count) {
441            case 0:
442                AW_advice("Not all formats can be auto-detected.\n"
443                          "Some need to be selected manually.",
444                          AW_ADVICE_TOGGLE,
445                          "No format auto-detected",
446                          "arb_import.hlp");
447
448                select = "unknown.ift";
449                break;
450
451            default:
452                AW_advice("Several import filters matched during auto-detection.\n"
453                          "Click 'AUTO DETECT' again to select next matching import-filter.",
454                          AW_ADVICE_TOGGLE,
455                          "Several formats detected",
456                          "arb_import.hlp");
457
458                // fall-through
459            case 1:
460                if (matched == -1) {
461                    // wrap around to top (while searching next matching filter)
462                    // or re-select the one matching filter (if it was previously selected)
463                    awti_assert(first != -1);
464                    matched = first;
465                }
466                awti_assert(matched != -1);
467                select = files[matched];  // select 1st matching filter
468                break;
469        }
470    }
471    else {
472        select = prev_selected;
473        aw_message(error);
474    }
475
476    awar_filter->write_string(select);
477    free(prev_selected);
478}
479
480int ArbImporter::next_file() {
481    if (in) fclose(in);
482    if (current_file_idx<0) current_file_idx = 0;
483
484    int result = 1;
485    while (result == 1 && filenames[current_file_idx]) {
486        const char *origin_file_name = filenames[current_file_idx++];
487
488        const char *sorigin   = strrchr(origin_file_name, '/');
489        if (!sorigin) sorigin = origin_file_name;
490        else sorigin++;
491
492        GB_ERROR  error          = NULp;
493        char     *mid_file_name  = NULp;
494        char     *dest_file_name = NULp;
495
496        if (ifo2 && ifo2->system) {
497            {
498                const char *sorigin_nameonly            = strrchr(sorigin, '/');
499                if (!sorigin_nameonly) sorigin_nameonly = sorigin;
500
501                char *mid_name = GB_unique_filename(sorigin_nameonly, "tmp");
502                mid_file_name  = GB_create_tempfile(mid_name);
503                free(mid_name);
504
505                if (!mid_file_name) error = GB_await_error();
506            }
507
508            if (!error) {
509                char *srt = GBS_global_string_copy("$<=%s:$>=%s", origin_file_name, mid_file_name);
510                char *sys = GBS_string_eval(ifo2->system, srt);
511
512                arb_progress::show_comment(GBS_global_string("exec '%s'", ifo2->system));
513
514                error                        = GBK_system(sys);
515                if (!error) origin_file_name = mid_file_name;
516
517                free(sys);
518                free(srt);
519            }
520        }
521
522        if (!error && ifo->system) {
523            {
524                const char *sorigin_nameonly            = strrchr(sorigin, '/');
525                if (!sorigin_nameonly) sorigin_nameonly = sorigin;
526
527                char *dest_name = GB_unique_filename(sorigin_nameonly, "tmp");
528                dest_file_name  = GB_create_tempfile(dest_name);
529                free(dest_name);
530
531                if (!dest_file_name) error = GB_await_error();
532            }
533
534            awti_assert(dest_file_name || error);
535
536            if (!error) {
537                char *srt = GBS_global_string_copy("$<=%s:$>=%s", origin_file_name, dest_file_name);
538                char *sys = GBS_string_eval(ifo->system, srt);
539
540                arb_progress::show_comment(GBS_global_string("Converting File %s", ifo->system));
541
542                error                        = GBK_system(sys);
543                if (!error) origin_file_name = dest_file_name;
544
545                free(sys);
546                free(srt);
547            }
548        }
549
550        if (!error) {
551            in = fopen(origin_file_name, "r");
552
553            if (in) {
554                result = 0;
555            }
556            else {
557                error = GBS_global_string("Error: Cannot open file %s\n", origin_file_name);
558            }
559        }
560
561        if (mid_file_name) {
562            awti_assert(GB_is_privatefile(mid_file_name, false));
563            GB_unlink_or_warn(mid_file_name, &error);
564            free(mid_file_name);
565        }
566        if (dest_file_name) {
567            GB_unlink_or_warn(dest_file_name, &error);
568            free(dest_file_name);
569        }
570
571        if (error) aw_message(error);
572    }
573
574    return result;
575}
576
577char *ArbImporter::read_line(int tab, char *sequencestart, char *sequenceend) {
578    /* two modes:   tab == 0 -> read single lines,
579       different files are separated by sequenceend,
580       tab != 0 join lines that start after position tab,
581       joined lines are separated by '|'
582       except lines that match sequencestart
583       (they may be part of sequence if read_this_sequence_line_too = 1 */
584
585    static char *in_queue  = NULp; // read data
586    static int   b2offset  = 0;
587    const int    BUFSIZE   = 8000;
588    const char  *SEPARATOR = "|";  // line separator
589
590    if (!ifo->b1) ARB_calloc(ifo->b1, BUFSIZE);
591    if (!ifo->b2) ARB_calloc(ifo->b2, BUFSIZE);
592
593    if (!in) {
594        if (next_file()) {
595            if (in_queue) {
596                char *s = in_queue;
597                in_queue = NULp;
598                return s;
599            }
600            return NULp;
601        }
602    }
603
604
605    if (!tab) {
606        if (in_queue) {
607            char *s = in_queue;
608            in_queue = NULp;
609            return s;
610        }
611        char *p = fgets_smartLF(ifo->b1, BUFSIZE-3, in);
612        if (!p) {
613            awti_assert(sequenceend); // @@@ what happens if SEQUENCEEND not specified? (print "(null)")
614            sprintf(ifo->b1, "%s", sequenceend);
615            if (in) { fclose(in); in = NULp; }
616            p = ifo->b1;
617        }
618        int len = strlen(p)-1;
619        while (len>=0) {
620            if (p[len] == '\n' || p[len] == 13) p[len--] = 0;
621            else break;
622        }
623        return ifo->b1;
624    }
625
626    b2offset = 0;
627    ifo->b2[0] = 0;
628
629    if (in_queue) {
630        b2offset = 0;
631        strncpy(ifo->b2+b2offset, in_queue, BUFSIZE - 4- b2offset);
632        b2offset += strlen(ifo->b2+b2offset);
633        in_queue = NULp;
634        if (GBS_string_matches(ifo->b2, sequencestart, GB_MIND_CASE)) return ifo->b2;
635    }
636    while (1) {
637        char *p = fgets_smartLF(ifo->b1, BUFSIZE-3, in);
638        if (!p) {
639            if (in) { fclose(in); in = NULp; }
640            break;
641        }
642        int len = strlen(p)-1;
643        while (len>=0) {
644            if (p[len] == '\n' || p[len] == 13) p[len--] = 0;
645            else break;
646        }
647
648
649        if (GBS_string_matches(ifo->b1, sequencestart, GB_MIND_CASE)) {
650            in_queue = ifo->b1;
651            return ifo->b2;
652        }
653
654        int i;
655        for (i=0; i<=tab; i++) if (ifo->b1[i] != ' ') break;
656
657        if (i < tab) {
658            in_queue = ifo->b1;
659            return ifo->b2;
660        }
661        strncpy(ifo->b2+b2offset, SEPARATOR, BUFSIZE - 4- b2offset);
662        b2offset += strlen(ifo->b2+b2offset);
663
664        p = ifo->b1;
665        if (b2offset>0) while (*p==' ') p++;    // delete spaces in second line
666
667        strncpy(ifo->b2+b2offset, p, BUFSIZE - 4- b2offset);
668        b2offset += strlen(ifo->b2+b2offset);
669    }
670    in_queue = NULp;
671    return ifo->b2;
672}
673
674static void write_entry(GBDATA *gb_main, GBDATA *gbd, const char *key, const char *str, const char *tag, int append, GB_TYPES type) {
675    if (!gbd) return;
676
677    {
678        while (str[0] == ' ' || str[0] == '\t' || str[0] == '|') str++;
679        int i = strlen(str)-1;
680        while (i >= 0 && (str[i] == ' ' || str[i] == '\t' || str[i] == '|' || str[i] == 13)) {
681            i--;
682        }
683
684        if (i<0) return;
685
686        i++;
687        if (str[i]) { // need to cut trailing whitespace?
688            char *copy = ARB_strndup(str, i);
689            write_entry(gb_main, gbd, key, copy, tag, append, type);
690            free(copy);
691            return;
692        }
693    }
694
695    GBDATA *gbk = GB_entry(gbd, key);
696
697    if (type != GB_STRING) {
698        if (!gbk) gbk=GB_create(gbd, key, type);
699        switch (type) {
700            case GB_INT:
701                GB_write_int(gbk, atoi(str));
702                break;
703            case GB_FLOAT:
704                GB_write_float(gbk, GB_atof(str));
705                break;
706            default:
707                awti_assert(0);
708                break;
709        }
710        return;
711    }
712
713    if (!gbk || !append) {
714        if (!gbk) gbk=GB_create(gbd, key, GB_STRING);
715
716        if (tag) {
717            GBS_strstruct *s = GBS_stropen(10000);
718            GBS_chrcat(s, '[');
719            GBS_strcat(s, tag);
720            GBS_strcat(s, "] ");
721            GBS_strcat(s, str);
722            char *val = GBS_strclose(s);
723            GB_write_string(gbk, val);
724            free(val);
725        }
726        else {
727            if (strcmp(key, "name") == 0) {
728                char *nstr = GBT_create_unique_species_name(gb_main, str);
729                GB_write_string(gbk, nstr);
730                free(nstr);
731            }
732            else {
733                GB_write_string(gbk, str);
734            }
735        }
736        return;
737    }
738
739    const char *strin = GB_read_char_pntr(gbk);
740
741    int   len    = strlen(str) + strlen(strin);
742    int   taglen = tag ? (strlen(tag)+2) : 0;
743    char *buf    = ARB_calloc<char>(len+2+taglen+1);
744
745    if (tag) {
746        char *regexp = ARB_alloc<char>(taglen+3);
747        sprintf(regexp, "*[%s]*", tag);
748
749        if (!GBS_string_matches(strin, regexp, GB_IGNORE_CASE)) { // if tag does not exist yet
750            sprintf(buf, "%s [%s] %s", strin, tag, str); // prefix with tag
751        }
752        free(regexp);
753    }
754
755    if (buf[0] == 0) {
756        sprintf(buf, "%s %s", strin, str);
757    }
758
759    GB_write_string(gbk, buf);
760    free(buf);
761    return;
762}
763
764static string expandSetVariables(const SetVariables& variables, const string& source, bool& error_occurred, const import_format *ifo) {
765    string                 dest;
766    string::const_iterator norm_start = source.begin();
767    string::const_iterator p          = norm_start;
768    error_occurred                    = false;
769
770    while (p != source.end()) {
771        if (*p == '$') {
772            ++p;
773            if (*p == '$') { // '$$' -> '$'
774                dest.append(1, *p);
775            }
776            else { // real variable
777                const string *value = variables.get(*p);
778                if (!value) {
779                    const string *user_error = ifo->variable_errors.get(*p);
780
781                    char *error = NULp;
782                    if (user_error) {
783                        error = GBS_global_string_copy("%s (variable '$%c' not set yet)", user_error->c_str(), *p);
784                    }
785                    else {
786                        error = GBS_global_string_copy("Variable '$%c' not set (missing SETVAR or SETGLOBAL?)", *p);
787                    }
788
789                    dest.append(GBS_global_string("<%s>", error));
790                    GB_export_error(error);
791                    free(error);
792                    error_occurred = true;
793                }
794                else {
795                    dest.append(*value);
796                }
797            }
798            ++p;
799        }
800        else {
801            dest.append(1, *p);
802            ++p;
803        }
804    }
805    return dest;
806}
807
808GB_ERROR ArbImporter::read_data(char *ali_name, int security_write) {
809    awti_assert(ifo->sequencestart); // otherwise format is invalid (assertion is no strict guarantee for validity!)
810
811    char *p;
812    while (1) { // search start of entry
813        p = read_line(0, ifo->sequencestart, ifo->sequenceend);
814        if (!p || !ifo->begin || GBS_string_matches(p, ifo->begin, GB_MIND_CASE)) break;
815    }
816    if (!p) return "Cannot find start of file: Wrong format or empty file";
817
818    static int counter       = 0; // note: dont reset counter (used for field 'name', improves uniqueness if no nameserver is used)
819    const  int start_counter = counter;
820
821    GBDATA  *gb_species_data = GBT_get_species_data(gb_import_main);
822    GBL_env  env(gb_import_main, NULp);
823
824    while (p) {
825        SetVariables variables(ifo->global_variables);
826
827        counter++;
828        const int  rel_counter = counter-start_counter;
829        GBDATA    *gb_species  = GB_create_container(gb_species_data, "species");
830
831        {
832            char text[100];
833            if (rel_counter % 10 == 0) {
834                sprintf(text, "Reading species %i", rel_counter);
835                arb_progress::show_comment(text);
836            }
837
838            sprintf(text, "spec%i", counter);
839            GBT_readOrCreate_char_pntr(gb_species, "name", text); // set default if missing
840        }
841
842        if (filenames[1]) {      // multiple files !!!
843            const char *f = strrchr(filenames[current_file_idx-1], '/');
844            if (!f) f = filenames[current_file_idx-1];
845            else f++;
846            write_entry(gb_import_main, gb_species, "file", f, ifo->filetag, 0, GB_STRING);
847        }
848
849        static bool  never_warn = false;
850        int          max_line   = never_warn ? INT_MAX : MAX_COMMENT_LINES;
851        GBL_call_env callEnv(gb_species, env);
852
853        for (int line=0; line<=max_line; line++) {
854            if (line == max_line) {
855                char *msg = GBS_global_string_copy("A database entry in file '%s' is longer than %i lines.\n"
856                                                   " * possible reasons: wrong input format or very long comment/data\n"
857                                                   " * please examine imported data if you decide to continue\n",
858                                                   filenames[current_file_idx] ? filenames[current_file_idx] : "<unknown>",
859                                                   line);
860
861                switch (aw_question("import_long_lines", msg, "Continue Reading,Continue Reading (Never ask again),Abort")) {
862                    case 0:
863                        max_line *= 2;
864                        break;
865                    case 1:
866                        max_line = INT_MAX;
867                        never_warn = true;
868                        break;
869                    case 2:
870                        break;
871                }
872
873                free(msg);
874            }
875            GB_ERROR error = NULp;
876            if (strlen(p) > ifo->tab) {
877                for (import_match *match = ifo->match; !error && match; match=match->next) {
878                    const char *what_error = NULp;
879                    if (GBS_string_matches(p, match->match, GB_MIND_CASE)) {
880                        char *dup = p+ifo->tab;
881                        while (*dup == ' ' || *dup == '\t') dup++;
882
883                        char *s    = NULp;
884                        char *dele = NULp;
885
886                        if (match->srt) {
887                            bool   err_flag;
888                            string expanded = expandSetVariables(variables, match->srt, err_flag, ifo);
889                            if (err_flag) error = GB_await_error();
890                            else {
891                                dele           = s = GBS_string_eval_in_env(dup, expanded.c_str(), callEnv);
892                                if (!s) error  = GB_await_error();
893                            }
894                            if (error) what_error = "SRT";
895                        }
896                        else {
897                            s = dup;
898                        }
899
900                        if (!error && match->aci) {
901                            bool   err_flag;
902                            string expanded     = expandSetVariables(variables, match->aci, err_flag, ifo);
903                            if (err_flag) error = GB_await_error();
904                            else {
905                                dup  = dele;
906                                dele = s = GB_command_interpreter_in_env(s, expanded.c_str(), callEnv);
907                                if (!s) error = GB_await_error();
908                                free(dup);
909                            }
910                            if (error) what_error = "ACI";
911                        }
912
913                        if (!error && (match->append || match->write)) {
914                            char *field = NULp;
915                            char *tag   = NULp;
916
917                            {
918                                bool   err_flag;
919                                string expanded_field = expandSetVariables(variables, string(match->append ? match->append : match->write), err_flag, ifo);
920                                if (err_flag) error   = GB_await_error();
921                                else   field          = GBS_string_2_key(expanded_field.c_str());
922                                if (error) what_error = match->append ? "APPEND" : "WRITE";
923                            }
924
925                            if (!error && match->mtag) {
926                                bool   err_flag;
927                                string expanded_tag = expandSetVariables(variables, string(match->mtag), err_flag, ifo);
928                                if (err_flag) error = GB_await_error();
929                                else   tag          = GBS_string_2_key(expanded_tag.c_str());
930                                if (error) what_error = "TAG";
931                            }
932
933                            if (!error) {
934                                write_entry(gb_import_main, gb_species, field, s, tag, bool(match->append), match->type);
935                            }
936                            free(tag);
937                            free(field);
938                        }
939
940                        if (!error && match->setvar) variables.set(match->setvar[0], s);
941                        free(dele);
942                    }
943
944                    if (error) {
945                        error = GBS_global_string("'%s'\nin %s of MATCH (defined at #%s)", error, what_error, match->defined_at);
946                    }
947                }
948            }
949
950            if (error) {
951                return GBS_global_string("%s\nwhile parsing line #%i of species #%i", error, line, rel_counter);
952            }
953
954            if (GBS_string_matches(p, ifo->sequencestart, GB_MIND_CASE)) goto read_sequence;
955
956            p = read_line(ifo->tab, ifo->sequencestart, ifo->sequenceend);
957            if (!p) break;
958        }
959        return GB_export_errorf("No Start of Sequence found (%i lines read)", max_line);
960
961    read_sequence :
962        {
963            char          *sequence;
964            GBS_strstruct *strstruct = GBS_stropen(5000);
965            int            linecnt;
966
967            for (linecnt = 0; ; linecnt++) {
968                if (linecnt || !ifo->read_this_sequence_line_too) {
969                    p = read_line(0, ifo->sequencestart, ifo->sequenceend);
970                }
971                if (!p) break;
972                if (ifo->sequenceend && GBS_string_matches(p, ifo->sequenceend, GB_MIND_CASE)) break;
973                if (strlen(p) <= ifo->sequencecolumn) continue;
974                GBS_strcat(strstruct, p+ifo->sequencecolumn);
975            }
976            sequence = GBS_strclose(strstruct);
977
978            GBDATA *gb_data = GBT_create_sequence_data(gb_species, ali_name, "data", GB_STRING, security_write);
979            if (ifo->sequencesrt) {
980                char *h = GBS_string_eval_in_env(sequence, ifo->sequencesrt, callEnv);
981                if (!h) return GB_await_error();
982                freeset(sequence, h);
983            }
984
985            if (ifo->sequenceaci) {
986                char *h = GB_command_interpreter_in_env(sequence, ifo->sequenceaci, callEnv);
987                free(sequence);
988                if (!h) return GB_await_error();
989                sequence = h;
990            }
991
992            GB_write_string(gb_data, sequence);
993
994            GBDATA *gb_acc = GB_search(gb_species, "acc", GB_FIND);
995            if (!gb_acc && ifo->autocreateacc) {
996                char buf[100];
997                long id = GBS_checksum(sequence, 1, ".-");
998                sprintf(buf, "ARB_%lX", id);
999                gb_acc = GB_search(gb_species, "acc", GB_STRING);
1000                GB_write_string(gb_acc, buf);
1001            }
1002            free(sequence);
1003        }
1004        while (1) {             // go to the start of an species
1005            if (!p || !ifo->begin || GBS_string_matches(p, ifo->begin, GB_MIND_CASE)) break;
1006            p = read_line(0, ifo->sequencestart, ifo->sequenceend);
1007        }
1008    }
1009    return NULp;
1010}
1011
1012GB_ERROR ArbImporter::import_data(AW_root *awr, const char *mask, bool keep_found_IDs) {
1013    // Import sequences into new or existing database
1014    // if 'keep_found_IDs' is true => do not ask (mode used by format-tester)
1015
1016    awti_assert(!GB_have_error());
1017
1018    bool     is_genom_db             = false;
1019    bool     delete_db_type_if_error = false; // delete db type (genome/normal) in case of error ?
1020    GB_ERROR error                   = NULp;
1021
1022    {
1023        bool           read_genom_db = wants_import_genome(awr);
1024        GB_transaction ta(gb_import_main);
1025
1026        delete_db_type_if_error = !GB_entry(gb_import_main, GENOM_DB_TYPE);
1027        is_genom_db             = GEN_is_genome_db(gb_import_main, read_genom_db);
1028
1029        if (read_genom_db!=is_genom_db) {
1030            if (is_genom_db) {
1031                error = "You can only import whole genom sequences into a genom database.";
1032            }
1033            else {
1034                error = "You can't import whole genom sequences into a non-genom ARB database.";
1035            }
1036            awti_assert(!GB_have_error());
1037            return error;
1038        }
1039    }
1040
1041    GB_change_my_security(gb_import_main, 6);
1042
1043    GB_begin_transaction(gb_import_main); // first transaction start
1044    char *ali_name;
1045    {
1046        char *ali = awr->awar(AWAR_IMPORT_ALI)->read_string();
1047        ali_name = GBS_string_eval(ali, SRT_AUTOCORRECT_ALINAME);
1048        free(ali);
1049    }
1050
1051    error = GBT_check_alignment_name(ali_name);
1052
1053    int ali_protection = awr->awar(AWAR_IMPORT_ALI_PROTECTION)->read_int();
1054    if (!error) {
1055        char *ali_type;
1056        ali_type = awr->awar(AWAR_IMPORT_ALI_TYPE)->read_string();
1057
1058        if (is_genom_db && strcmp(ali_type, "dna")!=0) {
1059            error = "You must set the alignment type to dna when importing genom sequences.";
1060        }
1061        else {
1062            GBT_create_alignment(gb_import_main, ali_name, 2000, 0, ali_protection, ali_type);
1063        }
1064        free(ali_type);
1065    }
1066
1067    bool ask_generate_names = true;
1068
1069    if (!error) {
1070        if (is_genom_db) {
1071            // import genome flatfile into ARB-genome database:
1072
1073            StrArray fnames;
1074            GBS_read_dir(fnames, mask, NULp);
1075            if (fnames.empty()) {
1076                error = GB_have_error() ? GB_await_error() : GBS_global_string("No file matched '%s'", mask);
1077            }
1078            else {
1079                int successfull_imports = 0;
1080                int failed_imports      = 0;
1081                int count;
1082
1083                for (count = 0; fnames[count]; ++count) ; // count filenames
1084
1085                GBDATA *gb_species_data = GBT_get_species_data(gb_import_main);
1086                ImportSession import_session(gb_species_data, count*10);
1087
1088                // close the above transaction and do each importfile in separate transaction
1089                // to avoid that all imports are undone by transaction abort happening in case of error
1090                GB_commit_transaction(gb_import_main);
1091
1092                arb_progress progress("Reading input files", count);
1093
1094                for (int curr = 0; !error && fnames[curr]; ++curr) {
1095                    GB_ERROR error_this_file =  NULp;
1096
1097                    GB_begin_transaction(gb_import_main);
1098                    {
1099                        const char *lslash = strrchr(fnames[curr], '/');
1100                        progress.subtitle(GBS_global_string("%i/%i: %s", curr+1, count, lslash ? lslash+1 : fnames[curr]));
1101                    }
1102
1103#if defined(DEBUG)
1104                    fprintf(stderr, "import of '%s'\n", fnames[curr]);
1105#endif // DEBUG
1106                    error_this_file = GI_importGenomeFile(import_session, fnames[curr], ali_name);
1107
1108                    if (!error_this_file) {
1109                        GB_commit_transaction(gb_import_main);
1110                        successfull_imports++;
1111                        delete_db_type_if_error = false;
1112                    }
1113                    else { // error occurred during import
1114                        error_this_file = GBS_global_string("'%s' not imported\nReason: %s", fnames[curr], error_this_file);
1115                        GB_warningf("Import error: %s", error_this_file);
1116                        GB_abort_transaction(gb_import_main);
1117                        failed_imports++;
1118                    }
1119
1120                    progress.inc_and_check_user_abort(error);
1121                }
1122
1123                if (!successfull_imports) {
1124                    error = "Nothing has been imported";
1125                }
1126                else {
1127                    GB_warningf("%i of %i files were imported with success", successfull_imports, (successfull_imports+failed_imports));
1128                }
1129
1130                // now open another transaction to "undo" the transaction close above
1131                GB_begin_transaction(gb_import_main);
1132            }
1133        }
1134        else {
1135            // import to non-genome ARB-db :
1136
1137            {
1138                // load import filter:
1139                char *file = awr->awar(AWAR_IMPORT_FORMATNAME)->read_string();
1140
1141                if (!strlen(file)) {
1142                    error = "Please select a form";
1143                }
1144                else {
1145                    error = read_format(file);
1146                    if (!error && ifo->new_format) {
1147                        ifo2 = ifo;
1148                        ifo  = NULp;
1149
1150                        error = read_format(ifo2->new_format);
1151                        if (!error) {
1152                            if (ifo->new_format) {
1153                                error = GBS_global_string("in line %zi of import filter '%s':\n"
1154                                                          "Only one level of form nesting (NEW_FORMAT) allowed",
1155                                                          ifo->new_format_lineno, name_only(ifo2->new_format));
1156                            }
1157                        }
1158                        if (error) {
1159                            error = GBS_global_string("in format used in line %zi of '%s':\n%s",
1160                                                      ifo2->new_format_lineno, name_only(file), error);
1161                        }
1162                    }
1163                }
1164                free(file);
1165            }
1166
1167            GBS_read_dir(filenames, mask, NULp);
1168            if (filenames.empty()) {
1169                error = GB_have_error() ? GB_await_error() : GBS_global_string("No file matched '%s'", mask);
1170            }
1171
1172            if (!error) {
1173                arb_progress progress("Reading input files");
1174
1175                error = read_data(ali_name, ali_protection);
1176                if (error) {
1177                    error = GBS_global_string("Error: %s\nwhile reading file %s", error, filenames[current_file_idx-1]);
1178                }
1179                else {
1180                    if (ifo->noautonames || (ifo2 && ifo2->noautonames)) {
1181                        ask_generate_names = false;
1182                    }
1183                    else {
1184                        ask_generate_names = true;
1185                    }
1186                }
1187            }
1188
1189            delete ifo;  ifo  = NULp;
1190            delete ifo2; ifo2 = NULp;
1191
1192            if (in) { fclose(in); in = NULp; }
1193
1194            filenames.erase();
1195            current_file_idx = 0;
1196        }
1197    }
1198    free(ali_name);
1199
1200    if (error) {
1201        GB_abort_transaction(gb_import_main);
1202
1203        if (delete_db_type_if_error) {
1204            // delete db type, if it was initialized above
1205            // (avoids 'can't import'-error, if file-type (genome-file/species-file) is changed after a failed try)
1206            GB_transaction  ta(gb_import_main);
1207            GBDATA         *db_type = GB_entry(gb_import_main, GENOM_DB_TYPE);
1208            if (db_type) GB_delete(db_type);
1209        }
1210    }
1211    else {
1212        arb_progress progress("Checking and Scanning database", 2+ask_generate_names); // 2 or 3 passes
1213        progress.subtitle("Pass 1: Check entries");
1214
1215        // scan for hidden/unknown fields :
1216        species_field_selection_list_rescan(gb_import_main, RESCAN_REFRESH);
1217        if (is_genom_db) gene_field_selection_list_rescan(gb_import_main, RESCAN_REFRESH);
1218
1219        GBT_mark_all(gb_import_main, 1);
1220        progress.inc();
1221        progress.subtitle("Pass 2: Check sequence lengths");
1222        GBT_check_data(gb_import_main, NULp);
1223
1224        GB_commit_transaction(gb_import_main);
1225        progress.inc();
1226
1227        if (ask_generate_names && !keep_found_IDs) {
1228            if (aw_question("generate_short_names",
1229                            "It's recommended to generate unique species identifiers now.\n",
1230                            "Generate unique species IDs,Use found IDs") == 0)
1231            {
1232                progress.subtitle("Pass 3: Generate unique species IDs");
1233                error = AW_select_nameserver(gb_import_main, gb_main_4_nameserver);
1234                if (!error) {
1235                    bool isDuplicatesWarning;
1236                    error = AWTC_pars_names(gb_import_main, &isDuplicatesWarning);
1237                    if (error && isDuplicatesWarning) {
1238                        aw_message(error); // warn, but ..
1239                        error = NULp;      // .. do not handle as error (otherwise import will abort)
1240                    }
1241                }
1242            }
1243            progress.inc();
1244        }
1245    }
1246
1247    GB_change_my_security(gb_import_main, 0);
1248
1249    // gb_main_4_nameserver = NULp; // this was only needed once. may interfere with import-tester
1250
1251    awti_assert(!GB_have_error());
1252    return error;
1253}
1254
1255void ArbImporter::import_and_continueOnSuccess(AW_window *aww) {
1256    AW_root  *awr   = aww->get_root();
1257    char     *mask  = awr->awar(AWAR_IMPORT_FILENAME)->read_string();
1258    GB_ERROR  error = import_data(awr, mask, false);
1259    if (error) {
1260        aw_message(error);
1261    }
1262    else {
1263        aww->hide(); // import window stays open in case of error
1264        after_import_cb(awr);
1265    }
1266    free(mask);
1267}
1268
1269class AliNameAndType {
1270    string name_, type_;
1271public:
1272    AliNameAndType(const char *ali_name, const char *ali_type) : name_(ali_name), type_(ali_type) {}
1273
1274    const char *name() const { return name_.c_str(); }
1275    const char *type() const { return type_.c_str(); }
1276};
1277
1278static AliNameAndType last_ali("ali_new", "rna"); // last selected ali for plain import (aka non-flatfile import)
1279
1280
1281void AWTI_import_set_ali_and_type(AW_root *awr, const char *ali_name, const char *ali_type, GBDATA *gbmain) {
1282    bool           switching_to_GENOM_ALIGNMENT = strcmp(ali_name, GENOM_ALIGNMENT) == 0;
1283    static GBDATA *last_valid_gbmain            = NULp;
1284
1285    if (gbmain) last_valid_gbmain = gbmain;
1286
1287    AW_awar *awar_name = awr->awar(AWAR_IMPORT_ALI);
1288    AW_awar *awar_type = awr->awar(AWAR_IMPORT_ALI_TYPE);
1289
1290    if (switching_to_GENOM_ALIGNMENT) {
1291        // read and store current settings
1292        char *curr_ali_name = awar_name->read_string();
1293        char *curr_ali_type = awar_type->read_string();
1294
1295        last_ali = AliNameAndType(curr_ali_name, curr_ali_type);
1296
1297        free(curr_ali_name);
1298        free(curr_ali_type);
1299    }
1300
1301    awar_name->write_string(ali_name);
1302    awar_type->write_string(ali_type);
1303
1304    if (last_valid_gbmain) { // detect default write protection for alignment
1305        GB_transaction ta(last_valid_gbmain);
1306        GBDATA *gb_ali            = GBT_get_alignment(last_valid_gbmain, ali_name);
1307        int     protection_to_use = 4;         // default protection
1308
1309        if (gb_ali) {
1310            GBDATA *gb_write_security = GB_entry(gb_ali, "alignment_write_security");
1311            if (gb_write_security) {
1312                protection_to_use = GB_read_int(gb_write_security);
1313            }
1314        }
1315        else {
1316            GB_clear_error();
1317        }
1318        awr->awar(AWAR_IMPORT_ALI_PROTECTION)->write_int(protection_to_use);
1319    }
1320}
1321
1322static void genom_flag_changed(AW_root *awr) {
1323    if (wants_import_genome(awr)) {
1324        AWTI_import_set_ali_and_type(awr, GENOM_ALIGNMENT, "dna", NULp);
1325        awr->awar(AWAR_IMPORT_FORMATFILTER)->write_string(".fit"); // *hack* to hide normal import filters
1326    }
1327    else {
1328        AWTI_import_set_ali_and_type(awr, last_ali.name(), last_ali.type(), NULp);
1329        awr->awar(AWAR_IMPORT_FORMATFILTER)->write_string(".ift");
1330    }
1331}
1332
1333// --------------------------------------------------------------------------------
1334
1335static ArbImporter *importer = NULp;
1336
1337void AWTI_cleanup_importer() {
1338    if (importer) {
1339#if defined(DEBUG)
1340        AWT_browser_forget_db(importer->peekImportDB());
1341#endif
1342        delete importer; // closes the import DB if it still is owned by the 'importer'
1343        importer = NULp;
1344    }
1345}
1346
1347static void import_window_close_cb(AW_window *aww, bool *doExit) {
1348    if (importer) {
1349        AWTI_cleanup_importer();
1350        if (*doExit) exit(EXIT_SUCCESS);
1351        else AW_POPDOWN(aww);
1352    }
1353    else {
1354        AW_POPDOWN(aww);
1355    }
1356}
1357
1358static void import_and_continue_cb(AW_window *aww) { importer->import_and_continueOnSuccess(aww); }
1359static void detect_input_format_cb(AW_window *aww) {
1360    if (wants_import_genome(aww->get_root())) {
1361        aw_message("Only works together with 'Import selected format'");
1362    }
1363    else {
1364        importer->detect_format(aww->get_root());
1365    }
1366}
1367
1368static void update_format_description(const char *ift) {
1369    const char *description = NULp;
1370
1371    if (ift && !ift[0]) {
1372        description = "";
1373    }
1374    else {
1375        GB_ERROR err = importer->read_format(ift);
1376
1377        if (err) {
1378            description = GBS_global_string("Error reading format:\n%s", err);
1379        }
1380        else {
1381            const import_format *ifo = importer->peek_format();
1382
1383            if      (!ifo || !ift[0])   description = "<no format selected>";
1384            else if (!ifo->description) description = "<no description>";
1385            else                        description = ifo->description;
1386        }
1387    }
1388    AW_root::SINGLETON->awar(AWAR_IMPORT_FORMAT_DESC)->write_string(description);
1389}
1390
1391void AWTI_set_importDB_pointer(GBDATA*& dbPtr) {
1392    awti_assert(importer);
1393    GBDATA *gb_imain = importer->peekImportDB();
1394    awti_assert(gb_imain);
1395    awti_assert(!dbPtr || dbPtr == gb_imain);
1396    dbPtr = gb_imain;
1397}
1398GBDATA *AWTI_acquire_imported_DB_and_cleanup_importer() {
1399    awti_assert(importer && importer->peekImportDB());
1400    GBDATA *gb_imported_main = importer->takeImportDB();
1401    AWTI_cleanup_importer();
1402    return gb_imported_main;
1403}
1404
1405static void create_import_awars(AW_root *awr, const char *def_importname) {
1406    {
1407        GBS_strstruct path(500);
1408        path.cat(GB_path_in_arbprop("filter"));
1409        path.put(':');
1410        path.cat(GB_path_in_ARBLIB("import"));
1411
1412        AW_create_fileselection_awars(awr, AWAR_IMPORT_FILEBASE,   ".",             "",     def_importname);
1413        AW_create_fileselection_awars(awr, AWAR_IMPORT_FORMATBASE, path.get_data(), ".ift", "*");
1414    }
1415
1416    awr->awar_string(AWAR_IMPORT_FORMAT_DESC,    "<undefined>");
1417    awr->awar_string(AWAR_IMPORT_ALI,            "<undefined>"); // these defaults are never used
1418    awr->awar_string(AWAR_IMPORT_ALI_TYPE,       "<undefined>"); // they are overwritten by AWTI_import_set_ali_and_type
1419    awr->awar_int   (AWAR_IMPORT_ALI_PROTECTION, 0);             // which is called via genom_flag_changed() below
1420
1421    awr->awar_int(AWAR_IMPORT_GENOM_DB, IMP_PLAIN_SEQUENCE);
1422    awr->awar_int(AWAR_IMPORT_AUTOCONF, 1);
1423
1424    awr->awar(AWAR_IMPORT_GENOM_DB)->add_callback(genom_flag_changed);
1425    genom_flag_changed(awr);
1426}
1427
1428void AWTI_open_import_window(AW_root *awr, const char *def_importname, bool do_exit, GBDATA *gb_main, const RootCallback& after_import_cb) {
1429    static AW_window_simple *aws = NULp;
1430
1431    if (!importer) {
1432        importer = new ArbImporter(after_import_cb);
1433
1434#if defined(DEBUG)
1435        AWT_announce_db_to_browser(importer->peekImportDB(), "New database (import)");
1436#endif // DEBUG
1437
1438        importer->set_db_4_nameserver(gb_main);
1439        if (!gb_main) {
1440            // control macros via temporary import DB (if no main DB available)
1441            GB_ERROR error = configure_macro_recording(awr, "ARB_IMPORT", importer->peekImportDB());
1442            aw_message_if(error);
1443        }
1444        else {
1445            awti_assert(got_macro_ability(awr));
1446        }
1447    }
1448
1449    static bool doExit;
1450    doExit = do_exit; // change/set behavior of CLOSE button
1451
1452    if (aws) {
1453        if (def_importname) {
1454            awr->awar(AWAR_IMPORT_FILENAME)->write_string(def_importname);
1455        }
1456    }
1457    else {
1458        create_import_awars(awr, def_importname);
1459
1460        aws = new AW_window_simple;
1461
1462        aws->init(awr, "ARB_IMPORT", "ARB IMPORT");
1463        aws->load_xfig("awt/import_db.fig");
1464
1465        aws->at("close");
1466        aws->callback(makeWindowCallback(import_window_close_cb, &doExit));
1467        aws->create_button("CLOSE", "CLOSE", "C");
1468
1469        aws->at("help");
1470        aws->callback(makeHelpCallback("arb_import.hlp"));
1471        aws->create_button("HELP", "HELP", "H");
1472
1473        AW_create_fileselection(aws, AWAR_IMPORT_FILEBASE,   "imp_", "PWD",     ANY_DIR,    true);  // select import filename
1474        AW_create_fileselection(aws, AWAR_IMPORT_FORMATBASE, "",     "ARBHOME", MULTI_DIRS, false); // select import filter
1475
1476        aws->at("auto");
1477        aws->callback(detect_input_format_cb);
1478        aws->create_autosize_button("AUTO_DETECT", "AUTO DETECT", "A");
1479
1480        aws->at("ali");
1481        aws->create_input_field(AWAR_IMPORT_ALI, 4);
1482
1483        aws->at("type");
1484        aws->create_option_menu(AWAR_IMPORT_ALI_TYPE, true);
1485        aws->insert_option        ("dna",     "d", "dna");
1486        aws->insert_default_option("rna",     "r", "rna");
1487        aws->insert_option        ("protein", "p", "ami");
1488        aws->update_option_menu();
1489
1490        aws->at("protect");
1491        aws->create_option_menu(AWAR_IMPORT_ALI_PROTECTION, true);
1492        aws->insert_option("0", "0", 0);
1493        aws->insert_option("1", "1", 1);
1494        aws->insert_option("2", "2", 2);
1495        aws->insert_option("3", "3", 3);
1496        aws->insert_default_option("4", "4", 4);
1497        aws->insert_option("5", "5", 5);
1498        aws->insert_option("6", "6", 6);
1499        aws->update_option_menu();
1500
1501        aws->at("genom");
1502        aws->create_toggle_field(AWAR_IMPORT_GENOM_DB);
1503        aws->sens_mask(AWM_EXP);
1504        aws->insert_toggle("Import genome data in EMBL, GenBank or DDBJ format", "e", IMP_GENOME_FLATFILE);
1505        aws->sens_mask(AWM_ALL);
1506        aws->insert_toggle("Import selected format", "f", IMP_PLAIN_SEQUENCE);
1507        aws->update_toggle_field();
1508
1509        aws->at("autoconf");
1510        aws->create_toggle(AWAR_IMPORT_AUTOCONF);
1511
1512        aws->at("desc");
1513        aws->create_text_field(AWAR_IMPORT_FORMAT_DESC);
1514
1515        aws->at("go");
1516        aws->callback(import_and_continue_cb);
1517        aws->highlight();
1518        aws->create_button("GO", "GO", "G", "+");
1519
1520        aws->at("test");
1521        aws->callback(AWTI_activate_import_test_window);
1522        aws->create_button("TEST", "Test", "T");
1523
1524        static FileWatch fwatch(AWAR_IMPORT_FORMATNAME, makeFileChangedCallback(update_format_description));
1525    }
1526    aws->activate();
1527}
1528
1529// --------------------------------------------------------------------------------
1530
1531#ifdef UNIT_TESTS
1532#ifndef TEST_UNIT_H
1533#include <test_unit.h>
1534#endif
1535
1536static void after_import_test_cb(AW_root*) {}
1537
1538void TEST_import_filters_loadable() {
1539    GB_shell    shell;
1540    ArbImporter testImporter(makeRootCallback(after_import_test_cb));
1541
1542    // Test that delivered filters are loadable w/o error:
1543    StrArray impFilt;
1544    GBS_read_dir(impFilt, GB_path_in_ARBLIB("import"), "/\\.ift$/"); // all filters in ../lib/import
1545    removeHiddenFiles(impFilt);
1546    TEST_EXPECT_EQUAL(impFilt.size(), 9);                            // amount of import filters
1547
1548    for (int i = 0; impFilt[i]; ++i) {
1549        const char *name = strrchr(impFilt[i], '/')+1;
1550        TEST_ANNOTATE(name);
1551        TEST_EXPECT_NO_ERROR(testImporter.read_format(impFilt[i]));
1552
1553        if (strcmp(name, "fasta_wgap.ift") == 0) {
1554            TEST_EXPECT_EQUAL(testImporter.peek_format()->description,
1555                              "Imports sequences in FASTA format (does not remove gaps)\n"
1556                              "Expected header: '>id fullname|...'");
1557        }
1558    }
1559}
1560
1561#endif // UNIT_TESTS
1562
1563// --------------------------------------------------------------------------------
1564
Note: See TracBrowser for help on using the repository browser.