fasta.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:20k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: fasta.cpp,v $
  4.  * PRODUCTION Revision 1000.2  2004/06/01 19:46:18  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.12
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: fasta.cpp,v 1000.2 2004/06/01 19:46:18 gouriano Exp $
  10. * ===========================================================================
  11. *
  12. *                            PUBLIC DOMAIN NOTICE
  13. *               National Center for Biotechnology Information
  14. *
  15. *  This software/database is a "United States Government Work" under the
  16. *  terms of the United States Copyright Act.  It was written as part of
  17. *  the author's official duties as a United States Government employee and
  18. *  thus cannot be copyrighted.  This software/database is freely available
  19. *  to the public for use. The National Library of Medicine and the U.S.
  20. *  Government have not placed any restriction on its use or reproduction.
  21. *
  22. *  Although all reasonable efforts have been taken to ensure the accuracy
  23. *  and reliability of the software and data, the NLM and the U.S.
  24. *  Government do not and cannot warrant the performance or results that
  25. *  may be obtained by using this software or data. The NLM and the U.S.
  26. *  Government disclaim all warranties, express or implied, including
  27. *  warranties of performance, merchantability or fitness for any particular
  28. *  purpose.
  29. *
  30. *  Please cite the author in any work or product based on this material.
  31. *
  32. * ===========================================================================
  33. *
  34. * Authors:  Aaron Ucko, NCBI;  Anatoliy Kuznetsov, NCBI.
  35. *
  36. * File Description:
  37. *   Reader for FASTA-format sequences.  (The writer is CFastaOStream, in
  38. *   src/objmgr/util/sequence.cpp.)
  39. *
  40. * ===========================================================================
  41. */
  42. #include <ncbi_pch.hpp>
  43. #include <objtools/readers/fasta.hpp>
  44. #include <objtools/readers/reader_exception.hpp>
  45. #include <corelib/ncbiutil.hpp>
  46. #include <util/format_guess.hpp>
  47. #include <objects/general/Object_id.hpp>
  48. #include <objects/seq/Bioseq.hpp>
  49. #include <objects/seq/Delta_ext.hpp>
  50. #include <objects/seq/Delta_seq.hpp>
  51. #include <objects/seq/IUPACaa.hpp>
  52. #include <objects/seq/IUPACna.hpp>
  53. #include <objects/seq/Seq_descr.hpp>
  54. #include <objects/seq/Seq_ext.hpp>
  55. #include <objects/seq/Seq_inst.hpp>
  56. #include <objects/seq/Seq_literal.hpp>
  57. #include <objects/seq/Seqdesc.hpp>
  58. #include <objects/seq/seqport_util.hpp>
  59. #include <objects/seqloc/Seq_id.hpp>
  60. #include <objects/seqloc/Seq_interval.hpp>
  61. #include <objects/seqloc/Seq_loc.hpp>
  62. #include <objects/seqloc/Seq_loc_mix.hpp>
  63. #include <objects/seqloc/Seq_point.hpp>
  64. #include <objects/seqset/Bioseq_set.hpp>
  65. BEGIN_NCBI_SCOPE
  66. BEGIN_SCOPE(objects)
  67. static SIZE_TYPE s_EndOfFastaID(const string& str, SIZE_TYPE pos)
  68. {
  69.     SIZE_TYPE vbar = str.find('|', pos);
  70.     if (vbar == NPOS) {
  71.         return NPOS; // bad
  72.     }
  73.     CSeq_id::E_Choice choice =
  74.         CSeq_id::WhichInverseSeqId(str.substr(pos, vbar - pos).c_str());
  75. #if 1
  76.     if (choice != CSeq_id::e_not_set) {
  77.         SIZE_TYPE vbar_prev = vbar;
  78.         int count;
  79.         for (count=0; ; ++count, vbar_prev = vbar) {
  80.             vbar = str.find('|', vbar_prev + 1);
  81.             if (vbar == NPOS) {
  82.                 break;
  83.             }
  84.             choice = CSeq_id::WhichInverseSeqId(
  85.                 str.substr(vbar_prev + 1, vbar - vbar_prev - 1).c_str());
  86.             if (choice != CSeq_id::e_not_set) {
  87.                 vbar = vbar_prev;
  88.                 break;
  89.             }
  90.         }
  91.     } else {
  92.         return NPOS; // bad
  93.     }
  94. #else
  95.     switch (choice) {
  96.     case CSeq_id::e_Patent: case CSeq_id::e_Other: // 3 args
  97.         vbar = str.find('|', vbar + 1);
  98.         // intentional fall-through - this allows us to correctly
  99.         // calculate the number of '|' separations for FastA IDs
  100.     case CSeq_id::e_Genbank:   case CSeq_id::e_Embl:    case CSeq_id::e_Pir:
  101.     case CSeq_id::e_Swissprot: case CSeq_id::e_General: case CSeq_id::e_Ddbj:
  102.     case CSeq_id::e_Prf:       case CSeq_id::e_Pdb:     case CSeq_id::e_Tpg:
  103.     case CSeq_id::e_Tpe:       case CSeq_id::e_Tpd:
  104.         // 2 args
  105.         if (vbar == NPOS) {
  106.             return NPOS; // bad
  107.         }
  108.         vbar = str.find('|', vbar + 1);
  109.         // intentional fall-through - this allows us to correctly
  110.         // calculate the number of '|' separations for FastA IDs
  111.     case CSeq_id::e_Local: case CSeq_id::e_Gibbsq: case CSeq_id::e_Gibbmt:
  112.     case CSeq_id::e_Giim:  case CSeq_id::e_Gi:
  113.         // 1 arg
  114.         if (vbar == NPOS) {
  115.             if (choice == CSeq_id::e_Other) {
  116.                 // this is acceptable - member is optional
  117.                 break;
  118.             }
  119.             return NPOS; // bad
  120.         }
  121.         vbar = str.find('|', vbar + 1);
  122.         break;
  123.     default: // unrecognized or not set
  124.         return NPOS; // bad
  125.     }
  126. #endif
  127.     return (vbar == NPOS) ? str.size() : vbar;
  128. }
  129. static void s_FixSeqData(CBioseq* seq)
  130. {
  131.     _ASSERT(seq);
  132.     CSeq_inst& inst = seq->SetInst();
  133.     switch (inst.GetRepr()) {
  134.     case CSeq_inst::eRepr_delta:
  135.     {
  136.         TSeqPos length = 0;
  137.         NON_CONST_ITERATE (CDelta_ext::Tdata, it,
  138.                            inst.SetExt().SetDelta().Set()) {
  139.             if ((*it)->IsLiteral()) {
  140.                 CSeq_literal& lit  = (*it)->SetLiteral();
  141.                 CSeq_data&    data = lit.SetSeq_data();
  142.                 if (data.IsIupacna()) {
  143.                     lit.SetLength(data.GetIupacna().Get().size());
  144.                     CSeqportUtil::Pack(&data);
  145.                 } else {
  146.                     string& s = data.SetIupacaa().Set();
  147.                     lit.SetLength(s.size());
  148.                     s.reserve(s.size()); // free extra allocation
  149.                 }
  150.                 length += lit.GetLength();
  151.             }
  152.         }
  153.         break;
  154.     }
  155.     case CSeq_inst::eRepr_raw:
  156.     {
  157.         CSeq_data& data = inst.SetSeq_data();
  158.         if (data.IsIupacna()) {
  159.             inst.SetLength(data.GetIupacna().Get().size());
  160.             CSeqportUtil::Pack(&data);
  161.         } else {
  162.             string& s = data.SetIupacaa().Set();
  163.             inst.SetLength(s.size());
  164.             s.reserve(s.size()); // free extra allocation
  165.         }        
  166.         break;
  167.     }
  168.     default: // especially not_set!
  169.         break;
  170.     }
  171. }
  172. void s_AddData(CSeq_inst& inst, const string& residues)
  173. {
  174.     CRef<CSeq_data> data;
  175.     if (inst.IsSetExt()  &&  inst.GetExt().IsDelta()) {
  176.         CDelta_ext::Tdata& delta_data = inst.SetExt().SetDelta().Set();
  177.         if (delta_data.empty()  ||  !delta_data.back()->IsLiteral()) {
  178.             CRef<CDelta_seq> delta_seq(new CDelta_seq);
  179.             delta_data.push_back(delta_seq);
  180.             data = &delta_seq->SetLiteral().SetSeq_data();
  181.         } else {
  182.             data = &delta_data.back()->SetLiteral().SetSeq_data();
  183.         }
  184.     } else {
  185.         data = &inst.SetSeq_data();
  186.     }
  187.     string* s = 0;
  188.     if (inst.GetMol() == CSeq_inst::eMol_aa) {
  189.         if (data->IsIupacaa()) {
  190.             s = &data->SetIupacaa().Set();
  191.         } else {
  192.             data->SetIupacaa().Set(residues);
  193.         }
  194.     } else {
  195.         if (data->IsIupacna()) {
  196.             s = &data->SetIupacna().Set();
  197.         } else {
  198.             data->SetIupacna().Set(residues);
  199.         }
  200.     }
  201.     if (s) {
  202.         // grow exponentially to avoid O(n^2) behavior
  203.         if (s->capacity() < s->size() + residues.size()) {
  204.             s->reserve(s->capacity()
  205.                        + max(residues.size(), s->capacity() / 2));
  206.         }
  207.         *s += residues;
  208.     }
  209. }
  210. static CSeq_inst::EMol s_ParseFastaDefline(CBioseq::TId& ids, string& title,
  211.                                            const string& line,
  212.                                            TReadFastaFlags flags, int* counter)
  213. {
  214.     SIZE_TYPE       start = 0;
  215.     CSeq_inst::EMol mol   = CSeq_inst::eMol_not_set;
  216.     do {
  217.         ++start;
  218.         SIZE_TYPE space = line.find_first_of(" t", start);
  219.         string    name  = line.substr(start, space - start), local;
  220.         if (flags & fReadFasta_NoParseID) {
  221.             local = name;
  222.         } else {
  223.             // try to parse out IDs
  224.             SIZE_TYPE pos = 0;
  225.             while (pos < name.size()) {
  226.                 SIZE_TYPE end = s_EndOfFastaID(name, pos);
  227.                 if (end == NPOS) {
  228.                     if (pos > 0) {
  229.                         NCBI_THROW2(CObjReaderParseException, eFormat,
  230.                                     "s_ParseFastaDefline: Bad ID "
  231.                                     + name.substr(pos),
  232.                                     pos);
  233.                     } else {
  234.                         local = name;
  235.                         break;
  236.                     }
  237.                 }
  238.                 CRef<CSeq_id> id(new CSeq_id(name.substr(pos, end - pos)));
  239.                 ids.push_back(id);
  240.                 if (mol == CSeq_inst::eMol_not_set
  241.                     &&  !(flags & fReadFasta_ForceType)) {
  242.                     CSeq_id::EAccessionInfo ai = id->IdentifyAccession();
  243.                     if (ai & CSeq_id::fAcc_nuc) {
  244.                         mol = CSeq_inst::eMol_na;
  245.                     } else if (ai & CSeq_id::fAcc_prot) {
  246.                         mol = CSeq_inst::eMol_aa;
  247.                     }
  248.                 }
  249.                 pos = end + 1;
  250.             }
  251.         }
  252.             
  253.         if ( !local.empty() ) {
  254.             ids.push_back(CRef<CSeq_id>
  255.                           (new CSeq_id(CSeq_id::e_Local, local, kEmptyStr)));
  256.         }
  257.         start = line.find('1', start);
  258.         if (space != NPOS  &&  title.empty()) {
  259.             title.assign(line, space + 1,
  260.                          (start == NPOS) ? NPOS : (start - space - 1));
  261.         }
  262.     } while (start != NPOS  &&  (flags & fReadFasta_AllSeqIds));
  263.     if (ids.empty()) {
  264.         CRef<CSeq_id> id(new CSeq_id);
  265.         id->SetLocal().SetId(++*counter);
  266.         ids.push_back(id);
  267.     }
  268.     return mol;
  269. }
  270. static void s_GuessMol(CSeq_inst::EMol& mol, const string& data,
  271.                        TReadFastaFlags flags, istream& in)
  272. {
  273.     if (mol != CSeq_inst::eMol_not_set) {
  274.         return; // already known; no need to guess
  275.     }
  276.     if (mol == CSeq_inst::eMol_not_set  &&  !(flags & fReadFasta_ForceType)) {
  277.         switch (CFormatGuess::SequenceType(data.data(), data.size())) {
  278.         case CFormatGuess::eNucleotide:  mol = CSeq_inst::eMol_na;  return;
  279.         case CFormatGuess::eProtein:     mol = CSeq_inst::eMol_aa;  return;
  280.         default:                         break;
  281.         }
  282.     }
  283.     // ForceType was set, or CFormatGuess failed, so we have to rely on
  284.     // explicit assumptions
  285.     if (flags & fReadFasta_AssumeNuc) {
  286.         _ASSERT(!(flags & fReadFasta_AssumeProt));
  287.         mol = CSeq_inst::eMol_na;
  288.     } else if (flags & fReadFasta_AssumeProt) {
  289.         mol = CSeq_inst::eMol_aa;
  290.     } else { 
  291.         NCBI_THROW2(CObjReaderParseException, eFormat,
  292.                     "ReadFasta: unable to deduce molecule type"
  293.                     " from IDs, flags, or sequence",
  294.                     in.tellg() - CT_POS_TYPE(0));
  295.     }
  296. }
  297. CRef<CSeq_entry> ReadFasta(CNcbiIstream& in, TReadFastaFlags flags,
  298.                            int* counter, vector<CConstRef<CSeq_loc> >* lcv)
  299. {
  300.     if ( !in ) {
  301.         NCBI_THROW2(CObjReaderParseException, eFormat,
  302.                     "ReadFasta: Input stream no longer valid",
  303.                     in.tellg() - CT_POS_TYPE(0));
  304.     } else {
  305.         CT_INT_TYPE c = in.peek();
  306.         if ( !strchr(">#!nr", CT_TO_CHAR_TYPE(c)) ) {
  307.             NCBI_THROW2
  308.                 (CObjReaderParseException, eFormat,
  309.                  "ReadFasta: Input doesn't start with a defline or comment",
  310.                  in.tellg() - CT_POS_TYPE(0));
  311.         }
  312.     }
  313.     CRef<CSeq_entry>       entry(new CSeq_entry);
  314.     CBioseq_set::TSeq_set& sset  = entry->SetSet().SetSeq_set();
  315.     CRef<CBioseq>          seq(0); // current Bioseq
  316.     string                 line;
  317.     TSeqPos                pos = 0, lc_start = 0;
  318.     bool                   was_lc = false;
  319.     CRef<CSeq_id>          best_id;
  320.     CRef<CSeq_loc>         lowercase(0);
  321.     int                    defcounter = 1;
  322.     if ( !counter ) {
  323.         counter = &defcounter;
  324.     }
  325.     while ( !in.eof() ) {
  326.         if ((flags & fReadFasta_OneSeq)  &&  seq.NotEmpty()
  327.             &&  (in.peek() == '>')) {
  328.             break;
  329.         }
  330.         NcbiGetlineEOL(in, line);
  331.         if (in.eof()  &&  line.empty()) {
  332.             break;
  333.         } else if (line.empty()) {
  334.             continue;
  335.         }
  336.         if (line[0] == '>') {
  337.             // new sequence
  338.             if (seq) {
  339.                 s_FixSeqData(seq);
  340.                 if (was_lc) {
  341.                     lowercase->SetPacked_int().AddInterval
  342.                         (*best_id, lc_start, pos);
  343.                 }
  344.             }
  345.             seq = new CBioseq;
  346.             if (flags & fReadFasta_NoSeqData) {
  347.                 seq->SetInst().SetRepr(CSeq_inst::eRepr_not_set);
  348.             } else {
  349.                 seq->SetInst().SetRepr(CSeq_inst::eRepr_raw);
  350.             }
  351.             {{
  352.                 CRef<CSeq_entry> entry2(new CSeq_entry);
  353.                 entry2->SetSeq(*seq);
  354.                 sset.push_back(entry2);
  355.             }}
  356.             string          title;
  357.             CSeq_inst::EMol mol = s_ParseFastaDefline(seq->SetId(), title,
  358.                                                       line, flags, counter);
  359.             if (mol == CSeq_inst::eMol_not_set
  360.                 &&  (flags & fReadFasta_NoSeqData)) {
  361.                 if (flags & fReadFasta_AssumeNuc) {
  362.                     _ASSERT(!(flags & fReadFasta_AssumeProt));
  363.                     mol = CSeq_inst::eMol_na;
  364.                 } else if (flags & fReadFasta_AssumeProt) {
  365.                     mol = CSeq_inst::eMol_aa;
  366.                 }
  367.             }
  368.             seq->SetInst().SetMol(mol);
  369.             if ( !title.empty() ) {
  370.                 CRef<CSeqdesc> desc(new CSeqdesc);
  371.                 desc->SetTitle(title);
  372.                 seq->SetDescr().Set().push_back(desc);
  373.             }
  374.             if (lcv) {
  375.                 pos       = 0;
  376.                 was_lc    = false;
  377.                 best_id   = FindBestChoice(seq->GetId(), CSeq_id::Score);
  378.                 lowercase = new CSeq_loc;
  379.                 lowercase->SetNull();
  380.                 lcv->push_back(lowercase);
  381.             }
  382.         } else if (line[0] == '#'  ||  line[0] == '!') {
  383.             continue; // comment
  384.         } else if ( !seq ) {
  385.             NCBI_THROW2
  386.                 (CObjReaderParseException, eFormat,
  387.                  "ReadFasta: No defline preceding data",
  388.                  in.tellg() - CT_POS_TYPE(0));
  389.         } else if ( !(flags & fReadFasta_NoSeqData) ) {
  390.             // These don't change, but the calls may be relatively expensive,
  391.             // esp. with ref-counted implementations.
  392.             SIZE_TYPE   line_size = line.size();
  393.             const char* line_data = line.data();
  394.             // actual data; may contain embedded junk
  395.             CSeq_inst&  inst      = seq->SetInst();
  396.             string      residues(line_size + 1, '');
  397.             char*       res_data  = const_cast<char*>(residues.data());
  398.             SIZE_TYPE   res_count = 0;
  399.             for (SIZE_TYPE i = 0;  i < line_size;  ++i) {
  400.                 char c = line_data[i];
  401.                 if (isalpha(c)) {
  402.                     if (lowercase) {
  403.                         bool is_lc = islower(c) ? true : false;
  404.                         if (is_lc && !was_lc) {
  405.                             lc_start = pos;
  406.                         } else if (was_lc && !is_lc) {
  407.                             lowercase->SetPacked_int().AddInterval
  408.                                 (*best_id, lc_start, pos);
  409.                         }
  410.                         was_lc = is_lc;
  411.                         ++pos;
  412.                     }
  413.                     res_data[res_count++] = toupper(c);
  414.                 } else if (c == '-'  &&  (flags & fReadFasta_ParseGaps)) {
  415.                     CDelta_ext::Tdata& d = inst.SetExt().SetDelta().Set();
  416.                     if (inst.GetRepr() == CSeq_inst::eRepr_raw) {
  417.                         CRef<CDelta_seq> ds(new CDelta_seq);
  418.                         inst.SetRepr(CSeq_inst::eRepr_delta);
  419.                         if (inst.IsSetSeq_data()) {
  420.                             ds->SetLiteral().SetSeq_data(inst.SetSeq_data());
  421.                             d.push_back(ds);
  422.                             inst.ResetSeq_data();
  423.                         }
  424.                     }
  425.                     if ( res_count ) {
  426.                         residues.resize(res_count);
  427.                         if (inst.GetMol() == CSeq_inst::eMol_not_set) {
  428.                             s_GuessMol(inst.SetMol(), residues, flags, in);
  429.                         }
  430.                         s_AddData(inst, residues);
  431.                     }
  432.                     {{
  433.                         CRef<CDelta_seq> gap(new CDelta_seq);
  434.                         gap->SetLoc().SetNull();
  435.                         d.push_back(gap);
  436.                     }}
  437.                     res_count = 0;
  438.                 } else if (c == ';') {
  439.                     continue; // skip rest of line
  440.                 }
  441.             }
  442.             if (inst.GetMol() == CSeq_inst::eMol_not_set) {
  443.                 s_GuessMol(inst.SetMol(), residues, flags, in);
  444.             }
  445.             
  446.             // Add the accumulated data...
  447.             residues.resize(res_count);
  448.             s_AddData(inst, residues);
  449.         }
  450.     }
  451.     if (seq) {
  452.         s_FixSeqData(seq);
  453.         if (was_lc) {
  454.             lowercase->SetPacked_int().AddInterval(*best_id, lc_start, pos);
  455.         }
  456.     }
  457.     // simplify if possible
  458.     if (sset.size() == 1) {
  459.         entry->SetSeq(*seq);
  460.     }
  461.     return entry;
  462. }
  463. void ReadFastaFileMap(SFastaFileMap* fasta_map, CNcbiIfstream& input)
  464. {
  465.     _ASSERT(fasta_map);
  466.     fasta_map->file_map.resize(0);
  467.     if (!input.is_open()) 
  468.         return;
  469.     while (!input.eof()) {
  470.         SFastaFileMap::SFastaEntry  fasta_entry;
  471.         fasta_entry.stream_offset = input.tellg() - CT_POS_TYPE(0);
  472.         CRef<CSeq_entry> se;
  473.         se = ReadFasta(input, fReadFasta_AssumeNuc | fReadFasta_OneSeq);
  474.         if (!se->IsSeq()) 
  475.             continue;
  476.         const CSeq_entry::TSeq& bioseq = se->GetSeq();
  477.         const CSeq_id* sid = bioseq.GetFirstId();
  478.         fasta_entry.seq_id = sid->AsFastaString();
  479.         if (bioseq.CanGetDescr()) {
  480.             const CSeq_descr& d = bioseq.GetDescr();
  481.             if (d.CanGet()) {
  482.                 const CSeq_descr_Base::Tdata& data = d.Get();
  483.                 if (!data.empty()) {
  484.                     CSeq_descr_Base::Tdata::const_iterator it = 
  485.                                                       data.begin();
  486.                     if (it != data.end()) {
  487.                         CRef<CSeqdesc> ref_desc = *it;
  488.                         ref_desc->GetLabel(&fasta_entry.description, 
  489.                                            CSeqdesc::eContent);
  490.                     }                                
  491.                 }
  492.             }
  493.         }
  494.         fasta_map->file_map.push_back(fasta_entry);
  495.         
  496.     } // while
  497. }
  498. END_SCOPE(objects)
  499. END_NCBI_SCOPE
  500. /*
  501. * ===========================================================================
  502. *
  503. * $Log: fasta.cpp,v $
  504. * Revision 1000.2  2004/06/01 19:46:18  gouriano
  505. * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.12
  506. *
  507. * Revision 1.12  2004/05/21 21:42:55  gorelenk
  508. * Added PCH ncbi_pch.hpp
  509. *
  510. * Revision 1.11  2004/02/19 22:57:52  ucko
  511. * Accommodate stricter implementations of CT_POS_TYPE.
  512. *
  513. * Revision 1.10  2003/12/05 03:00:36  ucko
  514. * Validate input better.
  515. *
  516. * Revision 1.9  2003/10/03 15:09:18  ucko
  517. * Tweak sequence string allocation to avoid O(n^2) performance from
  518. * linear resizing.
  519. *
  520. * Revision 1.8  2003/08/25 21:30:09  ucko
  521. * ReadFasta: tweak a bit to improve performance, and fix some bugs in
  522. * parsing gaps.
  523. *
  524. * Revision 1.7  2003/08/11 14:39:54  ucko
  525. * Populate "lowercase" with Packed_seqints rather than general Seq_loc_mixes.
  526. *
  527. * Revision 1.6  2003/08/08 21:29:12  dondosha
  528. * Changed type of lcase_mask in ReadFasta to vector of CConstRefs
  529. *
  530. * Revision 1.5  2003/08/07 21:13:21  ucko
  531. * Support a counter for assigning local IDs to sequences with no ID given.
  532. * Fix some minor bugs in lowercase-character support.
  533. *
  534. * Revision 1.4  2003/08/06 19:08:33  ucko
  535. * Slight interface tweak to ReadFasta: report lowercase locations in a
  536. * vector with one entry per Bioseq rather than a consolidated Seq_loc_mix.
  537. *
  538. * Revision 1.3  2003/06/23 20:49:11  kuznets
  539. * Changed to use Seq_id::AsFastaString() when reading fasta file map.
  540. *
  541. * Revision 1.2  2003/06/08 16:17:00  lavr
  542. * Heed MSVC int->bool performance warning
  543. *
  544. * Revision 1.1  2003/06/04 17:26:22  ucko
  545. * Split out from Seq_entry.cpp.
  546. *
  547. *
  548. * ===========================================================================
  549. */