source: tags/arb-6.0/CONVERTALN/embl.cxx

Last change on this file was 9225, checked in by westram, 11 years ago
  • rename unit test macros
    • TEST_ASSERT.. → TEST_EXPECT..
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 25.2 KB
Line 
1#include "embl.h"
2#include "genbank.h"
3#include "macke.h"
4#include "wrap.h"
5
6static void embl_continue_line(const char *pattern, char*& Str, Reader& reader) {
7    // if there are (numb) blanks at the beginning of line,
8    // it is a continue line of the current command.
9    int  ind;
10    char key[TOKENSIZE], temp[LINESIZE];
11
12    // check continue lines
13    for (++reader; reader.line(); ++reader) {
14        if (has_content(reader.line())) {
15            embl_key_word(reader.line(), 0, key);
16            if (!str_equal(pattern, key)) break;
17
18            // remove end-of-line, if there is any
19            ind = Skip_white_space(reader.line(), p_nonkey_start);
20            strcpy(temp, reader.line() + ind);
21            skip_eolnl_and_append_spaced(Str, temp);
22        }
23    }
24}
25
26static void embl_one_entry(Reader& reader, char*& entry, const char *key) {
27    // Read in one embl entry lines.
28    int index = Skip_white_space(reader.line(), p_nonkey_start);
29    freedup(entry, reader.line() + index);
30    embl_continue_line(key, entry, reader);
31}
32
33static void embl_date(Embl& embl, Reader& reader) {
34    // Read in embl DATE lines.
35    int index = Skip_white_space(reader.line(), p_nonkey_start);
36    freedup(embl.dateu, reader.line() + index);
37
38    ++reader;
39
40    char key[TOKENSIZE];
41    embl_key_word(reader.line(), 0, key);
42    if (str_equal(key, "DT")) {
43        index = Skip_white_space(reader.line(), p_nonkey_start);
44        freedup(embl.datec, reader.line() + index);
45        // skip the rest of DT lines
46        do {
47            ++reader;
48            if (!reader.line()) break;
49            embl_key_word(reader.line(), 0, key);
50        }
51        while (str_equal(key, "DT"));
52    }
53    else {
54        // always expect more than two DT lines
55        warning(33, "one DT line is missing");
56    }
57}
58
59static void embl_correct_title(Emblref& ref) {
60    // Check missing '"' at the both ends
61
62    terminate_with(ref.title, ';');
63
64    int len = str0len(ref.title);
65    if (len > 2 && (ref.title[0] != '"' || ref.title[len - 3] != '"')) {
66        char *temp = NULL;
67        if (ref.title[0] != '"')
68            temp = strdup("\"");
69        else
70            temp = strdup("");
71        Append(temp, ref.title);
72        if ((len > 2 && ref.title[len - 3]
73             != '"')) {
74            len = str0len(temp);
75            temp[len - 2] = '"';
76            terminate_with(temp, ';');
77        }
78        freedup(ref.title, temp);
79        free(temp);
80    }
81}
82
83int comment_subkey(const char *line, char *key) {
84    // Get the subkey-word (including delimiting ':') from a comment line
85    int len = parse_key_word(line, key, ":\t\n(");
86    if (!len) return 0;
87
88    if (line[len] == ':') {
89        key[len]   = ':';
90        key[len+1] = 0;
91    }
92    return len+1;
93}
94
95inline bool is_embl_comment(const char *line) { return line && line[0] == 'C' && line[1] == 'C'; }
96
97static void embl_one_comment_entry(char*& datastring, int start_index, Reader& reader) {
98    // Read in one embl sub-entry in comments lines.
99    // If it's not a RDP defined comment, you should not call this function.
100
101    int index = Skip_white_space(reader.line(), start_index);
102    freedup(datastring, reader.line() + index);
103
104    const int expectedIndent = RDP_CONTINUED_INDENT+RDP_SUBKEY_INDENT;
105
106    for (++reader;
107         is_embl_comment(reader.line()) && count_spaces(reader.line() + 2) >= expectedIndent;
108         ++reader)
109    {
110        index = Skip_white_space(reader.line(), p_nonkey_start + expectedIndent);
111
112        char temp[LINESIZE];
113        strcpy(temp, reader.line() + index);
114        skip_eolnl_and_append_spaced(datastring, temp);
115    }
116}
117
118static void embl_comments(Embl& embl, Reader& reader) {
119    // Read in embl comment lines.
120
121    for (; is_embl_comment(reader.line());) {
122        char key[TOKENSIZE];
123        int  index  = Skip_white_space(reader.line(), 5);
124        int  offset = comment_subkey(reader.line() + index, key);
125        index       = Skip_white_space(reader.line(), index + offset);
126
127        RDP_comment_parser one_comment_entry = embl_one_comment_entry;
128        RDP_comments&      comments          = embl.comments;
129
130        if (!parse_RDP_comment(comments, one_comment_entry, key, index, reader)) {
131            // other comments
132            Append(comments.others, reader.line() + 5);
133            ++reader;
134        }
135    }
136}
137
138static void embl_skip_unidentified(const char *pattern, Reader& reader) {
139    // if there are (numb) blanks at the beginning of line,
140    // it is a continue line of the current command.
141
142    for (++reader; reader.line(); ++reader) {
143        char  key[TOKENSIZE];
144        embl_key_word(reader.line(), 0, key);
145        if (!str_equal(key, pattern)) break;
146    }
147}
148
149void EmblParser::parse_section() {
150    char key[TOKENSIZE];
151    embl_key_word(reader.line(), 0, key);
152    state = ENTRY_STARTED;
153    parse_keyed_section(key);
154}
155
156static void embl_origin(Seq& seq, Reader& reader) {
157    // Read in embl sequence data.
158    ca_assert(seq.is_empty());
159
160    // read in whole sequence data
161    for (++reader;
162         reader.line() && !is_sequence_terminator(reader.line());
163         ++reader
164         )
165    {
166        const char *line = reader.line();
167        for (int idx = 5; line[idx]; ++idx) {
168            char ch = line[idx];
169            if (ch == ' ' || ch == '\n') continue;
170            if (idx>70) continue;
171            seq.add(ch);
172        }
173    }
174}
175
176void EmblParser::parse_keyed_section(const char *key) {
177    if (str_equal(key, "ID")) {
178        embl_one_entry(reader, embl.ID, key);
179    }
180    else if (str_equal(key, "DT")) {
181        embl_date(embl, reader);
182    }
183    else if (str_equal(key, "DE")) {
184        embl_one_entry(reader, embl.description, key);
185    }
186    else if (str_equal(key, "OS")) {
187        embl_one_entry(reader, embl.os, key);
188    }
189    else if (str_equal(key, "AC")) {
190        embl_one_entry(reader, embl.accession, key);
191    }
192    else if (str_equal(key, "KW")) {
193        embl_one_entry(reader, embl.keywords, key);
194
195        // correct missing '.'
196        if (!has_content(embl.keywords)) freedup(embl.keywords, ".\n");
197        else terminate_with(embl.keywords, '.');
198    }
199    else if (str_equal(key, "DR")) {
200        embl_one_entry(reader, embl.dr, key);
201    }
202    else if (str_equal(key, "RA")) {
203        Emblref& ref = embl.get_latest_ref();
204        embl_one_entry(reader, ref.author, key);
205        terminate_with(ref.author, ';');
206    }
207    else if (str_equal(key, "RT")) {
208        Emblref& ref = embl.get_latest_ref();
209        embl_one_entry(reader, ref.title, key);
210        embl_correct_title(ref);
211    }
212    else if (str_equal(key, "RL")) {
213        Emblref& ref = embl.get_latest_ref();
214        embl_one_entry(reader, ref.journal, key);
215        terminate_with(ref.journal, '.');
216    }
217    else if (str_equal(key, "RP")) {
218        Emblref& ref = embl.get_latest_ref();
219        embl_one_entry(reader, ref.processing, key);
220    }
221    else if (str_equal(key, "RN")) {
222        embl.resize_refs(embl.get_refcount()+1);
223        ++reader;
224    }
225    else if (str_equal(key, "CC")) {
226        embl_comments(embl, reader);
227    }
228    else if (str_equal(key, "SQ")) {
229        embl_origin(seq, reader);
230        state = ENTRY_COMPLETED;
231    }
232    else {
233        embl_skip_unidentified(key, reader);
234    }
235}
236
237void embl_key_word(const char *line, int index, char *key) {
238    parse_key_word(line+index, key, " \t\n");
239}
240
241static void embl_print_lines(Writer& write, const char *key, const char *content, const WrapMode& wrapMode) {
242    // Print EMBL entry and wrap around if line over EMBLMAXLINE.
243    ca_assert(strlen(key) == 2);
244
245    char prefix[TOKENSIZE];
246    sprintf(prefix, "%-*s", EMBLINDENT, key);
247
248    wrapMode.print(write, prefix, prefix, content, EMBLMAXLINE);
249}
250
251static bool embl_print_lines_if_content(Writer& write, const char *key, const char *content, const WrapMode& wrapMode, bool followed_by_spacer) {
252    if (has_content(content)) {
253        embl_print_lines(write, key, content, wrapMode);
254        if (followed_by_spacer) write.out("XX\n");
255        return true;
256    }
257    return false;
258}
259
260static void embl_print_comment_if_content(Writer& write, const char *key, const char *content) {
261    // Print one embl comment line, wrap around
262
263    if (!has_content(content)) return;
264
265    char first[LINESIZE]; sprintf(first, "CC%*s%s", (EMBLINDENT-2)+RDP_SUBKEY_INDENT, "", key);
266    char other[LINESIZE]; sprintf(other, "CC%*s", (EMBLINDENT-2)+RDP_SUBKEY_INDENT+RDP_CONTINUED_INDENT, "");
267    WrapMode(true).print(write, first, other, content, EMBLMAXLINE);
268}
269
270inline void embl_print_completeness(Writer& write, char compX, char X) {
271    if (compX == ' ') return;
272    ca_assert(compX == 'y' || compX == 'n');
273    write.outf("CC     %c' end complete: %s\n", X, compX == 'y' ? "Yes" : "No");
274}
275
276static void embl_out_comments(const Embl& embl, const Seq& seq, Writer& write) {
277    // Print out the comments part of EMBL format.
278
279    const OrgInfo& orginf = embl.comments.orginf;
280    if (orginf.exists()) {
281        write.out("CC   Organism information\n");
282
283        embl_print_comment_if_content(write, "Source of strain: ",   orginf.source);
284        embl_print_comment_if_content(write, "Culture collection: ", orginf.cultcoll);
285        embl_print_comment_if_content(write, "Former name: ",        orginf.formname);
286        embl_print_comment_if_content(write, "Alternate name: ",     orginf.nickname);
287        embl_print_comment_if_content(write, "Common name: ",        orginf.commname);
288        embl_print_comment_if_content(write, "Host organism: ",      orginf.hostorg);
289    }
290
291    const SeqInfo& seqinf = embl.comments.seqinf;
292    if (seqinf.exists()) {
293        write.outf("CC   Sequence information (bases 1 to %d)\n", seq.get_len());
294
295        embl_print_comment_if_content(write, "RDP ID: ",                      seqinf.RDPid);
296        embl_print_comment_if_content(write, "Corresponding GenBank entry: ", seqinf.gbkentry);
297        embl_print_comment_if_content(write, "Sequencing methods: ",          seqinf.methods);
298
299        embl_print_completeness(write, seqinf.comp5, '5');
300        embl_print_completeness(write, seqinf.comp3, '3');
301    }
302
303    embl_print_lines_if_content(write, "CC", embl.comments.others, WrapMode("\n"), true);
304}
305
306static void embl_out_origin(const Seq& seq, Writer& write) {
307    // Print out the sequence data of EMBL format.
308    BaseCounts bases;
309    seq.count(bases);
310    write.outf("SQ   Sequence %d BP; %d A; %d C; %d G; %d T; %d other;\n",
311               seq.get_len(), bases.a, bases.c, bases.g, bases.t, bases.other);
312
313    seq.out(write, EMBL);
314}
315
316void embl_out_header(const Embl& embl, const Seq& seq, Writer& write) {
317    WrapMode wrapWords(true);
318    WrapMode neverWrap(false);
319
320    embl_print_lines_if_content(write, "ID", embl.ID,        neverWrap, true);
321    embl_print_lines_if_content(write, "AC", embl.accession, wrapWords, true);
322
323    {
324        bool dt1 = embl_print_lines_if_content(write, "DT", embl.dateu, neverWrap, false);
325        bool dt2 = embl_print_lines_if_content(write, "DT", embl.datec, neverWrap, false);
326        if (dt1 || dt2) write.out("XX\n");
327    }
328
329    embl_print_lines_if_content(write, "DE", embl.description, wrapWords,     true);
330    embl_print_lines_if_content(write, "KW", embl.keywords,    WrapMode(";"), true);
331
332    if (has_content(embl.os)) {
333        embl_print_lines(write, "OS", embl.os, wrapWords);
334        write.out("OC   No information.\n");
335        write.out("XX\n");
336    }
337
338    // GenbankRef
339    for (int indi = 0; indi < embl.get_refcount(); indi++) {
340        const Emblref& ref = embl.get_ref(indi);
341
342        write.outf("RN   [%d]\n", indi + 1);
343        embl_print_lines_if_content(write, "RP", ref.processing, neverWrap, false);
344        embl_print_lines_if_content(write, "RA", ref.author, WrapMode(","), false);
345
346        if (has_content(ref.title)) embl_print_lines(write, "RT", ref.title, wrapWords);
347        else write.out("RT   ;\n");
348
349        embl_print_lines_if_content(write, "RL", ref.journal, wrapWords, false);
350        write.out("XX\n");
351    }
352
353    if (has_content(embl.dr)) {
354        embl_print_lines(write, "DR", embl.dr, wrapWords);
355        write.out("XX\n");
356    }
357
358    embl_out_comments(embl, seq, write);
359}
360
361void embl_out(const Embl& embl, const Seq& seq, Writer& write) {
362    // Output EMBL data.
363    embl_out_header(embl, seq, write);
364    embl_out_origin(seq, write);
365}
366
367static char *etog_author(char *Str) {
368    // Convert EMBL author format to Genbank author format.
369    int  indi, indk, len, index;
370    char token[TOKENSIZE], *author;
371
372    author = strdup("");
373    for (indi = index = 0, len = str0len(Str) - 1; indi < len; indi++, index++) {
374        if (Str[indi] == ',' || Str[indi] == ';') {
375            token[index--] = '\0';
376            if (has_content(author)) {
377                Append(author, (Str[indi] == ',') ? "," : " and");
378            }
379            // search backward to find the first blank and replace the blank by ','
380            for (indk = 0; index > 0 && indk == 0; index--)
381                if (token[index] == ' ') {
382                    token[index] = ',';
383                    indk = 1;
384                }
385            Append(author, token);
386            index = (-1);
387        }
388        else
389            token[index] = Str[indi];
390    }
391    Append(author, "\n");
392    return (author);
393}
394static char *etog_journal(const char *eJournal) {
395    // Convert journal part from EMBL to GenBank format.
396    char *new_journal = 0;
397    char  token[TOKENSIZE];
398
399    scan_token_or_die(token, eJournal);
400    if (str_equal(token, "(in)") == 1 || str_equal(token, "Submitted") || str_equal(token, "Unpublished")) {
401        // remove trailing '.'
402        int len     = str0len(eJournal);
403        ca_assert(eJournal[len-2] == '.');
404        new_journal = strndup(eJournal, len-2);
405        Append(new_journal, "\n");
406    }
407    else {
408        const char *colon = strchr(eJournal, ':');
409
410        if (colon) {
411            const char *p1 = strchr(colon+1, '(');
412            if (p1) {
413                const char *p2 = strchr(p1+1, ')');
414                if (p2 && strcmp(p2+1, ".\n") == 0) {
415                    new_journal = Reallocspace(new_journal, str0len(eJournal)+1+1);
416
417                    int l1 = colon-eJournal;
418                    int l2 = p1-colon-1;
419                    int l3 = p2-p1+1;
420
421                    char *pos = new_journal;
422
423                    memcpy(pos, eJournal, l1); pos += l1;
424                    memcpy(pos, ", ",     2);  pos += 2;
425                    memcpy(pos, colon+1,  l2); pos += l2;
426                    memcpy(pos, " ",      1);  pos += 1;
427                    memcpy(pos, p1,       l3); pos += l3;
428                    memcpy(pos, "\n",     2);
429                }
430            }
431        }
432
433        if (!new_journal) {
434            warningf(148, "Removed unknown journal format: %s", eJournal);
435            new_journal = no_content();
436        }
437    }
438
439    return new_journal;
440}
441static void etog_convert_references(const Embl& embl, GenBank& gbk) {
442    // Convert reference from EMBL to GenBank format.
443    int  indi, len, start, end;
444    char temp[LONGTEXT];
445
446    gbk.resize_refs(embl.get_refcount());
447
448    for (indi = 0; indi < embl.get_refcount(); indi++) {
449        const Emblref& ref  = embl.get_ref(indi);
450        GenbankRef&    gref = gbk.get_ref(indi);
451
452        if (has_content(ref.processing) &&
453            sscanf(ref.processing, "%d %d", &start, &end) == 2)
454        {
455            end *= -1; // will get negative from sscanf
456            sprintf(temp, "%d  (bases %d to %d)\n", (indi + 1), start, end);
457        }
458        else {
459            sprintf(temp, "%d\n", (indi + 1));
460        }
461
462        freedup(gref.ref, temp);
463
464        if (has_content(ref.title) && ref.title[0] != ';') {
465            // remove '"' and ';', if there is any
466            len = str0len(ref.title);
467            if (len > 2 && ref.title[0] == '"' && ref.title[len - 2] == ';' && ref.title[len - 3] == '"') {
468                ref.title[len - 3] = '\n';
469                ref.title[len - 2] = '\0';
470                freedup(gref.title, ref.title+1);
471                ref.title[len - 3] = '"';
472                ref.title[len - 2] = ';';
473            }
474            else {
475                freedup(gref.title, ref.title);
476            }
477        }
478        else {
479            freeset(gref.title, no_content());
480        }
481
482        freeset(gref.author, has_content(ref.author) ? etog_author(ref.author) : no_content());
483        freeset(gref.journal, has_content(ref.journal) ? etog_journal(ref.journal) : no_content());
484
485        freeset(gref.standard, no_content());
486    }
487}
488
489int etog(const Embl& embl, GenBank& gbk, const Seq& seq) { // __ATTR__USERESULT
490    // Convert from embl to genbank format.
491    int  indi;
492    char key[TOKENSIZE], temp[LONGTEXT];
493    char t1[TOKENSIZE], t2[TOKENSIZE], t3[TOKENSIZE];
494
495    embl_key_word(embl.ID, 0, key);
496    if (has_content(embl.dr)) {
497        // get short_id from DR line if there is RDP def.
498        strcpy(t3, "dummy");
499        ASSERT_RESULT(int, 3, sscanf(embl.dr, "%s %s %s", t1, t2, t3));
500        if (str_equal(t1, "RDP;")) {
501            if (!str_equal(t3, "dummy")) {
502                strcpy(key, t3);
503            }
504            else
505                strcpy(key, t2);
506            key[str0len(key) - 1] = '\0';        // remove '.'
507        }
508    }
509    strcpy(temp, key);
510
511    // LOCUS
512    for (indi = str0len(temp); indi < 13; temp[indi++] = ' ') {}
513    {
514        const char *date = has_content(embl.dateu) ? embl.dateu : today_date();
515        sprintf((temp + 10), "%7d bp    RNA             RNA       %s\n",
516                seq.get_len(),
517                genbank_date(date));
518    }
519    freedup(gbk.locus, temp);
520
521    // DEFINITION
522    if (copy_content(gbk.definition, embl.description)) terminate_with(gbk.definition, '.');
523
524    // SOURCE and DEFINITION if not yet defined
525    if (copy_content(gbk.source, embl.os)) {
526        freedup(gbk.organism, embl.os);
527        if (!has_content(embl.description)) {
528            freedup(gbk.definition, embl.os);
529        }
530    }
531
532    // COMMENT GenBank entry
533    copy_content(gbk.accession, embl.accession);
534    if (has_content(embl.keywords) && embl.keywords[0] != '.') {
535        freedup(gbk.keywords, embl.keywords);
536    }
537
538    etog_convert_references(embl, gbk);
539    gbk.comments.set_content_from(embl.comments);
540
541    return (1);
542}
543
544int etom(const Embl& embl, Macke& macke, const Seq& seq) { // __ATTR__USERESULT
545    // Convert from embl format to Macke format.
546    GenBank gbk;
547    return etog(embl, gbk, seq) && gtom(gbk, macke);
548}
549
550// --------------------------------------------------------------------------------
551
552#ifdef UNIT_TESTS
553#include <test_unit.h>
554
555#define TEST_EXPECT_ETOG_JOURNAL_PARSES(i,o)              \
556    do {                                                  \
557        char *dup = strdup(i);                            \
558        char *res = etog_journal(dup);                    \
559        TEST_EXPECT_EQUAL(res, o);                        \
560        free(res);                                        \
561        free(dup);                                        \
562    } while (0)
563
564void TEST_BASIC_etog_journal() {
565    // behavior documented in r6943:
566    TEST_EXPECT_ETOG_JOURNAL_PARSES("Gene 134:283-287(1993).\n",
567                                    "Gene 134, 283-287 (1993)\n");
568    TEST_EXPECT_ETOG_JOURNAL_PARSES("J. Exp. Med. 179:1809-1821(1994).\n",
569                                    "J. Exp. Med. 179, 1809-1821 (1994)\n");
570    TEST_EXPECT_ETOG_JOURNAL_PARSES("Unpublished whatever.\n",
571                                    "Unpublished whatever\n");
572    TEST_EXPECT_ETOG_JOURNAL_PARSES("bla bla bla.\n",
573                                    "\n"); // skips if can't parse
574    TEST_EXPECT_ETOG_JOURNAL_PARSES("bla bla bla\n",
575                                    "\n");
576}
577
578#endif // UNIT_TESTS
579
580static char *gtoe_author(char *author) {
581    // Convert GenBank author to EMBL author.
582    int   indi, len, index, odd;
583    char *auth, *Str;
584
585    // replace " and " by ", "
586    auth = nulldup(author);
587    if ((index = find_pattern(auth, " and ")) > 0) {
588        auth[index] = '\0';
589        Str = nulldup(auth);
590        auth[index] = ' ';      // remove '\0' for free space later
591        Append(Str, ",");
592        Append(Str, auth + index + 4);
593    }
594    else
595        Str = nulldup(author);
596
597    for (indi = 0, len = str0len(Str), odd = 1; indi < len; indi++) {
598        if (Str[indi] == ',') {
599            if (odd) {
600                Str[indi] = ' ';
601                odd = 0;
602            }
603            else {
604                odd = 1;
605            }
606        }
607    }
608
609    freenull(auth);
610    return (Str);
611}
612static char *gtoe_journal(char *Str) {
613    // Convert GenBank journal to EMBL journal.
614    char token[TOKENSIZE], *journal;
615    int  indi, indj, index, len;
616
617    if (scan_token(token, Str)) {
618        if (str_equal(token, "(in)") == 1 || str_equal(token, "Unpublished") || str_equal(token, "Submitted")) {
619            journal = nulldup(Str);
620            terminate_with(journal, '.');
621            return (journal);
622        }
623    }
624
625    journal = nulldup(Str);
626    for (indi = indj = index = 0, len = str0len(journal); indi < len; indi++, indj++) {
627        if (journal[indi] == ',') {
628            journal[indi] = ':';
629            indi++;             // skip blank after ','
630            index = 1;
631        }
632        else if (journal[indi] == ' ' && index) {
633            indj--;
634        }
635        else
636            journal[indj] = journal[indi];
637    }
638
639    journal[indj] = '\0';
640    terminate_with(journal, '.');
641    return (journal);
642}
643static void gtoe_reference(const GenBank& gbk, Embl& embl) {
644    // Convert references from GenBank to EMBL.
645    if (gbk.has_refs()) {
646        embl.resize_refs(gbk.get_refcount());
647    }
648
649    for (int indi = 0; indi < gbk.get_refcount(); indi++) {
650        Emblref&          ref  = embl.get_ref(indi);
651        const GenbankRef& gref = gbk.get_ref(indi);
652
653        freedup(ref.title, gref.title);
654        embl_correct_title(ref);
655
656        freeset(ref.journal, gtoe_journal(gref.journal));
657        terminate_with(ref.journal, '.');
658
659        freeset(ref.author, gtoe_author(gref.author));
660        terminate_with(ref.author, ';');
661
662        // create processing information
663        int refnum, start = 0, end = 0;
664        char t1[TOKENSIZE], t2[TOKENSIZE], t3[TOKENSIZE];
665
666        if (!gref.ref || sscanf(gref.ref, "%d %s %d %s %d %s", &refnum, t1, &start, t2, &end, t3) != 6) {
667            start = 0;
668            end = 0;
669        }
670
671        freenull(ref.processing);
672        if (start || end) ref.processing = strf("%d-%d\n", start, end);
673        else              ref.processing = no_content();
674
675    }
676}
677
678int gtoe(const GenBank& gbk, Embl& embl, const Seq& seq) { // __ATTR__USERESULT
679    // Genbank to EMBL.
680    {
681        char temp[LONGTEXT];
682        strcpy(temp, gbk.get_id());
683
684        upcase(temp); // Adjust short-id, EMBL short_id always upper case
685        for (int indi = min(str0len(temp), 9); indi < 10; indi++)
686            temp[indi] = ' ';
687
688        sprintf(temp + 10, "preliminary; RNA; UNA; %d BP.\n", seq.get_len());
689        freedup(embl.ID, temp);
690    }
691
692    // accession number
693    if (has_content(gbk.accession))
694        // take just the accession num, no version num.
695        freedup(embl.accession, gbk.accession);
696
697    // date
698    {
699        char *date = gbk.get_date();
700
701        freeset(embl.dateu, strf("%s (Rel. 1, Last updated, Version 1)\n", date));
702        freeset(embl.datec, strf("%s (Rel. 1, Created)\n", date));
703
704        free(date);
705    }
706
707    // description
708    copy_content(embl.description, gbk.definition);
709    // EMBL KW line
710    if (copy_content(embl.keywords, gbk.keywords)) {
711        terminate_with(embl.keywords, '.');
712    }
713    else {
714        freedup(embl.keywords, ".\n");
715    }
716
717    copy_content(embl.os, gbk.organism); // EMBL OS line
718    // reference
719    gtoe_reference(gbk, embl);
720
721    // EMBL DR line
722    {
723        char token[TOKENSIZE];
724        char temp[LONGTEXT];
725
726        scan_token_or_die(token, gbk.locus); // short_id
727        if (has_content(gbk.comments.seqinf.RDPid)) {
728            char rdpid[TOKENSIZE];
729            scan_token_or_die(rdpid, gbk.comments.seqinf.RDPid);
730            sprintf(temp, "RDP; %s; %s.\n", rdpid, token);
731        }
732        else {
733            sprintf(temp, "RDP; %s.\n", token);
734        }
735        freedup(embl.dr, temp);
736    }
737    embl.comments.set_content_from(gbk.comments);
738
739    return (1);
740}
741
742static int partial_mtoe(const Macke& macke, Embl& embl) {
743    // Handle subspecies information when converting from Macke to EMBL.
744    char*& others = embl.comments.others;
745
746    if (has_content(macke.strain)) {
747        int  ridx        = skip_pattern(others, "*source:");
748        bool have_strain = ridx >= 0 && stristr(others+ridx, "strain=");
749
750        if (!have_strain) {
751            if (!has_content(others)) freenull(others);
752            Append(others, "*source: strain=");
753            Append(others, macke.strain);
754            if (!is_end_mark(others[str0len(others) - 2])) skip_eolnl_and_append(others, ";\n");
755        }
756    }
757
758    if (has_content(macke.subspecies)) {
759        int  ridx       = skip_pattern(others, "*source:");
760        bool have_subsp = ridx >= 0 && find_subspecies(others+ridx, '=') >= 0;
761
762        if (!have_subsp) {
763            if (!has_content(others)) freenull(others);
764            Append(others, "*source: subspecies=");
765            Append(others, macke.subspecies);
766            if (!is_end_mark(others[str0len(others) - 2])) skip_eolnl_and_append(others, ";\n");
767        }
768    }
769
770    return (1);
771}
772
773int mtoe(const Macke& macke, Embl& embl, const Seq& seq) { // __ATTR__USERESULT
774    GenBank gbk;
775    return mtog(macke, gbk, seq) && gtoe(gbk, embl, seq) && partial_mtoe(macke, embl);
776}
777
778bool EmblSwissprotReader::read_one_entry(Seq& seq) {
779    data.reinit();
780    if (!EmblParser(data, seq, *this).parse_entry()) abort();
781    return ok();
782}
Note: See TracBrowser for help on using the repository browser.