root/trunk/CONVERTALN/mg.cxx

Revision 8607, 17.4 KB (checked in by westram, 5 weeks ago)

merge from e4fix [8135] [8136] [8137] [8138] [8139] [8140] [8141] [8142] [8143] [8144] [8222]
this revives the reverted patches [8129] [8130] [8131] [8132]

  • fixes
    • some free/delete mismatches
    • wrong definition of ORF objects (Level was no bit value)
    • amino consensus (failed for columns only containing 'C')
  • rename
    • AA_sequence_term -> orf_term
    • ED4_sequence_terminal_basic -> ED4_abstract_sequence_terminal
  • cleaned up hierarchy dumps
  • tweaked is_terminal()/to_terminal()
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1// genbank and Macke converting program
2
3#include "genbank.h"
4#include "macke.h"
5
6static int paren_string(char *line, char *pstring, int index) {
7    int len       = str0len(line);
8    int paren_num = 0;
9    int indk;
10
11    for (indk = 0; index < len; index++) {
12        if (paren_num >= 1)
13            pstring[indk++] = line[index];
14        if (line[index] == '(')
15            paren_num++;
16        if (line[index] == ')')
17            paren_num--;
18    }
19    if (indk == 0)
20        return (-1);
21    pstring[--indk] = '\0';
22    return (index);
23}
24
25static void get_atcc_string(const char *line, char *temp, int index) {
26    // Get the rest of the line until reaching certain terminators, such as ';', ',', '.',...
27
28    int len       = str0len(line);
29    int paren_num = 0;
30    int indk;
31
32    for (indk = 0; index < len; index++, indk++) {
33        temp[indk] = line[index];
34        if (temp[indk] == '(')
35            paren_num++;
36        if (temp[indk] == ')')
37            if (paren_num == 0)
38                break;
39            else
40                paren_num--;
41        else if (paren_num == 0 && (temp[indk] == ';' || temp[indk] == '.' || temp[indk] == ',' || temp[indk] == '/' || temp[indk] == '\n'))
42            break;
43    }
44    temp[indk] = '\0';
45}
46
47static char *get_atcc(const Macke& macke, char *source) {
48    static int cc_num = 16;
49    static const char *CC[16] = {
50        "ATCC", "CCM", "CDC", "CIP", "CNCTC",
51        "DSM", "EPA", "JCM", "NADC", "NCDO", "NCTC", "NRCC",
52        "NRRL", "PCC", "USDA", "VPI"
53    };
54
55    int  indi, indj, index;
56    int  length;
57    char buffer[LONGTEXT], temp[LONGTEXT], pstring[LONGTEXT];
58    char atcc[LONGTEXT];
59
60    atcc[0] = '\0';
61    for (indi = 0; indi < cc_num; indi++) {
62        index = 0;
63        while ((index = paren_string(source, pstring, index)) > 0) {
64            if ((indj = find_pattern(pstring, CC[indi])) >= 0) {
65                // skip the key word
66                indj += str0len(CC[indi]);
67                // skip blank spaces
68                indj = Skip_white_space(pstring, indj);
69                // get strain
70                get_atcc_string(pstring, buffer, indj);
71                sprintf(temp, "%s %s", CC[indi], buffer);
72                length = str0len(atcc);
73                if (length > 0) {
74                    atcc[length] = '\0';
75                    strcat(atcc, ", ");
76                }
77                strcat(atcc, temp);
78            }
79        }
80    }
81    // append eoln to the atcc string
82    length = str0len(atcc);
83    if (macke.atcc) {
84        macke.atcc[length] = '\0';
85    }
86    strcat(atcc, "\n");
87    return (nulldup(atcc));
88}
89
90static char *genbank_get_atcc(const GenBank& gbk, const Macke& macke) {
91    // Get atcc from SOURCE line in Genbank data file.
92    char  temp[LONGTEXT];
93    char *atcc;
94
95    atcc = NULL;
96    // get culture collection #
97    if (has_content(gbk.source)) {
98        atcc = get_atcc(macke, gbk.source);
99    }
100    if (!has_content(atcc) && has_content(macke.strain)) {
101        // add () to macke strain to be processed correctly
102        sprintf(temp, "(%s)", macke.strain);
103        atcc = get_atcc(macke, temp);
104    }
105    return atcc;
106}
107
108void Macke::add_35end_remark(char end35, char yn) {
109    if (yn == ' ') return;
110
111    char *content = strf("%c' end complete:  %s\n", end35, yn == 'y' ? "Yes" : "No");
112    add_remark(content);
113    free(content);
114}
115
116void Macke::add_remarks_from(const GenbankRef& ref) {
117    add_remark_if_content("ref:",      ref.ref);
118    add_remark_if_content("auth:",     ref.author);
119    add_remark_if_content("jour:",     ref.journal);
120    add_remark_if_content("title:",    ref.title);
121    add_remark_if_content("standard:", ref.standard);
122}
123
124void Macke::add_remarks_from(const OrgInfo& orginf) {
125    add_remark_if_content("Source of strain:",   orginf.source);       // copy source of strain
126    add_remark_if_content("Former name:",        orginf.formname);     // copy former name
127    add_remark_if_content("Alternate name:",     orginf.nickname);     // copy alternate name
128    add_remark_if_content("Common name:",        orginf.commname);     // copy common name
129    add_remark_if_content("Host organism:",      orginf.hostorg);      // copy host organism
130}
131
132void Macke::add_remarks_from(const RDP_comments& comments) {
133    add_remarks_from(comments.orginf);
134    add_remarks_from(comments.seqinf);
135
136    // other comments, not RDP DataBase specially defined
137    int len = str0len(comments.others);
138    if (len > 0) {
139        for (int indi = 0, indj = 0; indi < len; indi++) {
140            char temp[LONGTEXT];
141            temp[indj++] = comments.others[indi];
142            if (comments.others[indi] == '\n' || comments.others[indi] == '\0') {
143                temp[indj] = '\0';
144                add_remark(temp);
145                indj       = 0;
146            }
147        }
148    }
149}
150
151void Macke::add_remarks_from(const SeqInfo& seqinf) {
152    add_remark_if_content("RDP ID:",             seqinf.RDPid);        // copy RDP ID
153    add_remark_if_content("Sequencing methods:", seqinf.methods);      // copy methods
154
155    add_35end_remark('3', seqinf.comp3);
156    add_35end_remark('5', seqinf.comp5);
157}
158
159void Macke::add_remarks_from(const GenBank& gbk) {
160    // Create Macke remarks.
161
162    // REFERENCE the first reference
163    if (gbk.has_refs())
164        add_remark_if_content("ref:", gbk.get_ref(0).ref);
165
166    // The rest of the REFERENCES
167    for (int indi = 1; indi < gbk.get_refcount(); indi++) {
168        add_remarks_from(gbk.get_ref(indi));
169    }
170
171    add_remark_if_content("KEYWORDS:",           gbk.keywords);        // copy keywords as remark
172    add_remark_if_content("GenBank ACCESSION:",  gbk.accession);       // copy accession as remark when genbank entry also exists.
173    add_remarks_from(gbk.comments);
174}
175
176static void correct_subspecies(char *subspecies) {
177    // Remove the strain information in subspecies which is sometime mistakenly written into it.
178    int indj;
179
180    if ((indj = find_pattern(subspecies, "str\n")) >= 0 || (indj = find_strain(subspecies, 0)) >= 0) {
181        ca_assert(subspecies[indj-1] == ' '); // assume to overwrite a space
182        subspecies[indj - 1] = '\n';
183        subspecies[indj]     = '\0';
184    }
185}
186
187static void check_consistency(const char *what, char* const& var, const char *New) {
188    if (has_content(var)) {
189        if (!str_equal(var, New)) {
190            warningf(20, "Inconsistent %s definitions detected:\n"
191                     "    %s"
192                     "and %s", what, var, New);
193        }
194    }
195    else {
196        strcpy(var, New);
197    }
198}
199
200static void get_string(char *temp, const char *line, int index) {
201    // Get the rest of the line until reaching certain terminators,
202    // such as ';', ',', '.',...
203    // Always append "\n" at the end of the result.
204
205    index = Skip_white_space(line, index);
206
207    int len       = str0len(line);
208    int paren_num = 0;
209    int indk;
210
211    for (indk = 0; index < len; index++, indk++) {
212        temp[indk] = line[index];
213        if (temp[indk] == '(')
214            paren_num++;
215        if (temp[indk] == ')')
216            if (paren_num == 0)
217                break;
218            else
219                paren_num--;
220        else if (temp[indk] == '\n' || (paren_num == 0 && temp[indk] == ';'))
221            break;
222    }
223    if (indk > 1 && is_end_mark(temp[indk - 1]))
224        indk--;
225    temp[indk++] = '\n';
226    temp[indk] = '\0';
227}
228
229static void copy_subspecies_and_check_consistency(char* const& subspecies, const char *from, int indj) {
230    char temp[LONGTEXT];
231    get_string(temp, from, indj);
232    correct_subspecies(temp);
233    check_consistency("subspecies", subspecies, temp);
234}
235static void copy_strain_and_check_consistency(char* const& strain, const char *from, int indj) {
236    char temp[LONGTEXT];
237    get_string(temp, from, indj);
238    check_consistency("strain", strain, temp);
239}
240
241static void check_strain_from(char* const& strain, const char *from) {
242    if (has_content(from)) {
243        int indj = skip_strain(from, ' ');
244        if (indj >= 0) copy_strain_and_check_consistency(strain, from, indj);
245    }
246}
247
248static char *genbank_get_strain(const GenBank& gbk) {
249    // Get strain from DEFINITION, COMMENT or SOURCE line in Genbank data file.
250    char strain[LONGTEXT];
251
252    strain[0] = '\0';
253
254    if (has_content(gbk.comments.others)) {
255        int indj = find_pattern(gbk.comments.others, "*source:");
256        if (indj >= 0) {
257            int indk = skip_pattern(gbk.comments.others + indj, "strain=");
258            if (indk >= 0) copy_strain_and_check_consistency(strain, gbk.comments.others, indj+indk);
259        }
260    }
261
262    check_strain_from(strain, gbk.definition);
263    check_strain_from(strain, gbk.source);
264
265    return nulldup(strain);
266}
267
268static char *genbank_get_subspecies(const GenBank& gbk) {
269    // Get subspecies information from SOURCE, DEFINITION, or COMMENT line of Genbank data file.
270    int  indj;
271    char subspecies[LONGTEXT];
272
273    subspecies[0] = '\0';
274
275    if (has_content(gbk.definition)) {
276        if ((indj = skip_pattern(gbk.definition, "subsp. ")) >= 0) {
277            copy_subspecies_and_check_consistency(subspecies, gbk.definition, indj);
278        }
279    }
280    if (has_content(gbk.comments.others)) {
281        if ((indj = find_pattern(gbk.comments.others, "*source:")) >= 0) {
282            int indk = skip_subspecies(gbk.comments.others + indj, '=');
283            if (indk >= 0) {
284                copy_subspecies_and_check_consistency(subspecies, gbk.comments.others, indj+indk);
285            }
286        }
287    }
288
289    if (has_content(gbk.source)) {
290        if ((indj = skip_subspecies(gbk.source, ' ')) >= 0) {
291            copy_subspecies_and_check_consistency(subspecies, gbk.source, indj);
292        }
293    }
294
295    return nulldup(subspecies);
296}
297
298static void mtog_decode_ref_and_remarks(const Macke& macke, GenBank& gbk) {
299    // Decode remarks of Macke to GenBank format.
300    ca_assert(gbk.get_refcount() == 0);
301
302    if (has_content(macke.author))  freedup(gbk.get_new_ref().author, macke.author);
303    if (has_content(macke.journal)) freedup(gbk.get_latest_ref().journal, macke.journal);
304    if (has_content(macke.title))   freedup(gbk.get_latest_ref().title, macke.title);
305
306    bool first_ref = true;
307
308    RDP_comments& comments = gbk.comments;
309    OrgInfo&      orginf   = comments.orginf;
310    SeqInfo&      seqinf   = comments.seqinf;
311
312    for (int ridx = 0; ridx < macke.get_rem_count(); ridx++) {
313        char key[TOKENSIZE];
314        int offset = macke_key_word(macke.get_rem(ridx), 0, key);
315
316        if (str_equal(key, "ref")) {
317            GenbankRef& ref = first_ref ? gbk.get_latest_ref() : gbk.get_new_ref();
318            freeset(ref.ref, macke.copy_multi_rem(ridx, offset));
319            first_ref = false;
320        }
321        else if (str_equal(key, "auth")) {
322            freeset(gbk.get_latest_ref().author, macke.copy_multi_rem(ridx, offset));
323        }
324        else if (str_equal(key, "title")) {
325            freeset(gbk.get_latest_ref().title, macke.copy_multi_rem(ridx, offset));
326        }
327        else if (str_equal(key, "jour")) {
328            freeset(gbk.get_latest_ref().journal, macke.copy_multi_rem(ridx, offset));
329        }
330        else if (str_equal(key, "standard")) {
331            freeset(gbk.get_latest_ref().standard, macke.copy_multi_rem(ridx, offset));
332        }
333        else if (str_equal(key, "KEYWORDS")) {
334            freeset(gbk.keywords, macke.copy_multi_rem(ridx, offset));
335            terminate_with(gbk.keywords, '.');
336        }
337        else if (str_equal(key, "GenBank ACCESSION")) {
338            freeset(gbk.accession, macke.copy_multi_rem(ridx, offset));
339        }
340        else if (str_equal(key, "Source of strain")) {
341            freeset(orginf.source, macke.copy_multi_rem(ridx, offset));
342        }
343        else if (str_equal(key, "Former name")) {
344            freeset(orginf.formname, macke.copy_multi_rem(ridx, offset));
345        }
346        else if (str_equal(key, "Alternate name")) {
347            freeset(orginf.nickname, macke.copy_multi_rem(ridx, offset));
348        }
349        else if (str_equal(key, "Common name")) {
350            freeset(orginf.commname, macke.copy_multi_rem(ridx, offset));
351        }
352        else if (str_equal(key, "Host organism")) {
353            freeset(orginf.hostorg, macke.copy_multi_rem(ridx, offset));
354        }
355        else if (str_equal(key, "RDP ID")) {
356            freeset(seqinf.RDPid, macke.copy_multi_rem(ridx, offset));
357        }
358        else if (str_equal(key, "Sequencing methods")) {
359            freeset(seqinf.methods, macke.copy_multi_rem(ridx, offset));
360        }
361        else if (str_equal(key, "3' end complete")) {
362            scan_token_or_die(key, macke.get_rem(ridx) + offset);
363            seqinf.comp3 = str_equal(key, "Yes") ? 'y' : 'n';
364        }
365        else if (str_equal(key, "5' end complete")) {
366            scan_token_or_die(key, macke.get_rem(ridx) + offset);
367            seqinf.comp5 = str_equal(key, "Yes") ? 'y' : 'n';
368        }
369        else { // other (non-interpreted) comments
370            Append(comments.others, macke.get_rem(ridx));
371        }
372    }
373}
374
375static void mtog_genbank_def_and_source(const Macke& macke, GenBank& gbk) {
376    // Define GenBank DEFINITION and SOURCE lines the way RDP group likes.
377    copy_content(gbk.definition, macke.name);
378    if (has_content(macke.subspecies)) {
379        if (!has_content(gbk.definition)) {
380            warning(22, "Genus and Species not defined");
381            skip_eolnl_and_append(gbk.definition, "subsp. ");
382        }
383        else
384            skip_eolnl_and_append(gbk.definition, " subsp. ");
385
386        Append(gbk.definition, macke.subspecies);
387    }
388
389    if (has_content(macke.strain)) {
390        if (!has_content(gbk.definition)) {
391            warning(23, "Genus and Species and Subspecies not defined");
392            skip_eolnl_and_append(gbk.definition, "str. ");
393        }
394        else
395            skip_eolnl_and_append(gbk.definition, " str. ");
396
397        Append(gbk.definition, macke.strain);
398    }
399
400    // create SOURCE line, temp.
401    if (copy_content(gbk.source, gbk.definition)) terminate_with(gbk.source, '.');
402
403    // append keyword to definition, if there is keyword.
404    if (has_content(gbk.keywords)) {
405        if (has_content(gbk.definition))
406            skip_eolnl_and_append(gbk.definition, "; \n");
407
408        // Here keywords must be ended by a '.' already
409        skip_eolnl_and_append(gbk.definition, gbk.keywords);
410    }
411    else
412        skip_eolnl_and_append(gbk.definition, ".\n");
413}
414
415int mtog(const Macke& macke, GenBank& gbk, const Seq& seq) { // __ATTR__USERESULT
416    // Convert Macke format to Genbank format.
417    int  indi;
418    char temp[LONGTEXT];
419
420    strcpy(temp, macke.seqabbr);
421
422    for (indi = str0len(temp); indi < 13; temp[indi++] = ' ') {}
423
424    if (has_content(macke.date))
425        sprintf((temp + 10), "%7d bp    RNA             RNA       %s\n", seq.get_len(), genbank_date(macke.date));
426    else
427        sprintf((temp + 10), "%7d bp    RNA             RNA       %s\n", seq.get_len(), genbank_date(today_date()));
428
429    freedup(gbk.locus, temp);
430
431    // GenBank ORGANISM
432    if (copy_content(gbk.organism, macke.name)) terminate_with(gbk.organism, '.');
433
434    RDP_comments& comments = gbk.comments;
435    OrgInfo& orginf = comments.orginf;
436    SeqInfo& seqinf = comments.seqinf;
437
438    copy_content(seqinf.methods, macke.rna);
439
440    if (!copy_content(seqinf.gbkentry, macke.acs))
441        copy_content(seqinf.gbkentry, macke.nbk);
442
443    copy_content(orginf.cultcoll, macke.atcc);
444    mtog_decode_ref_and_remarks(macke, gbk);
445
446    // final conversion of cultcoll
447    if (!has_content(orginf.cultcoll)) copy_content(orginf.cultcoll, macke.atcc);
448
449    // define GenBank DEFINITION, after GenBank KEYWORD is defined.
450    mtog_genbank_def_and_source(macke, gbk);
451
452    return (1);
453}
454
455int gtom(const GenBank& gbk, Macke& macke) { // __ATTR__USERESULT
456    // Convert from Genbank format to Macke format.
457    char temp[LONGTEXT], buffer[TOKENSIZE];
458    char genus[TOKENSIZE], species[TOKENSIZE];
459
460    // copy sequence abbr, assume every entry in gbk must end with \n\0
461    // no '\n' at the end of the string
462    genbank_key_word(gbk.locus, 0, temp);
463    freedup(macke.seqabbr, temp);
464
465    // copy name and definition
466    if (!copy_content(macke.name, gbk.organism) && has_content(gbk.definition)) {
467        ASSERT_RESULT(int, 2, sscanf(gbk.definition, "%s %s", genus, species));
468
469        int last = str0len(species)-1;
470        if (species[last] == ';') species[last] = '\0';
471
472        freeset(macke.name, strf("%s %s\n", genus, species));
473    }
474
475    const OrgInfo& orginf = gbk.comments.orginf;
476    const SeqInfo& seqinf = gbk.comments.seqinf;
477
478    copy_content(macke.atcc, orginf.cultcoll); // copy cultcoll name and number
479    copy_content(macke.rna,  seqinf.methods); // copy rna(methods)
480
481    freeset(macke.date, gbk.get_date()); Append(macke.date, "\n");
482
483    // copy genbank entry  (gbkentry has higher priority than gbk.accession)
484    if (!copy_content(macke.acs, seqinf.gbkentry)) {
485        if (has_content(gbk.accession) && !str_equal(gbk.accession, "No information\n")) {
486            scan_token_or_die(buffer, gbk.accession);
487            strcat(buffer, "\n");
488        }
489        else {
490            strcpy(buffer, "\n");
491        }
492        freedup(macke.acs, buffer);
493    }
494
495    // copy the first reference from GenBank to Macke
496    if (gbk.has_refs()) {
497        copy_content(macke.author,  gbk.get_ref(0).author);
498        copy_content(macke.journal, gbk.get_ref(0).journal);
499        copy_content(macke.title,   gbk.get_ref(0).title);
500    }
501    // the rest of references are put into remarks, rem:.....
502    macke.add_remarks_from(gbk);
503
504    // adjust the strain, subspecies, and atcc information
505    freeset(macke.strain,     genbank_get_strain(gbk));
506    freeset(macke.subspecies, genbank_get_subspecies(gbk));
507    if (!has_content(macke.atcc)) {
508        freeset(macke.atcc, genbank_get_atcc(gbk, macke));
509    }
510
511    return (1);
512}
Note: See TracBrowser for help on using the browser.