Catch annotation sequences that don't end with newline
[mussa.git] / alg / sequence.cpp
index 2e845c67bdfaa84d5843e0b05a5e3a766e363eaf..b39c4d45eef964f7e6bea050be7d16cce9bba386 100644 (file)
@@ -32,6 +32,7 @@ namespace fs = boost::filesystem;
 namespace spirit = boost::spirit;
 
 #include "alg/sequence.hpp"
+#include "io.hpp"
 #include "mussa_exceptions.hpp"
 
 #include <string>
@@ -162,22 +163,6 @@ Sequence &Sequence::operator=(const Sequence& s)
   return *this;
 }
 
-static void multiplatform_getline(std::istream& in, std::string& line)
-{
-  line.clear();
-  char c;
-  in.get(c);
-  while(in.good() and !(c == '\012' or c == '\015') ) {
-    line.push_back(c);
-    in.get(c);
-  }
-  // if we have cr-lf eat it
-  c = in.peek();
-  if (c=='\012' or c == '\015') {
-    in.get();
-  }
-}
-
 void Sequence::load_fasta(fs::path file_path, int seq_num, int start_index, int end_index)
 {
   load_fasta(file_path, reduced_nucleic_alphabet, seq_num, start_index, end_index);
@@ -339,6 +324,21 @@ Sequence::load_annot(fs::path file_path, int start_index, int end_index)
     throw mussa_load_error("Error loading annotation file " + file_path.string());
   }
 
+  try {  
+    load_annot(data_stream, start_index, end_index);
+  }  catch(annotation_load_error e) {
+    std::ostringstream msg;
+    msg << file_path.native_file_string()
+        << " "
+        << e.what();
+    throw annotation_load_error(msg.str());
+  }
+  data_stream.close();
+}
+
+void
+Sequence::load_annot(std::istream& data_stream, int start_index, int end_index)
+{
   // so i should probably be passing the parse function some iterators
   // but the annotations files are (currently) small, so i think i can 
   // get away with loading the whole file into memory
@@ -348,17 +348,8 @@ Sequence::load_annot(fs::path file_path, int start_index, int end_index)
     data_stream.get(c);
     data.push_back(c);
   }
-  data_stream.close();
 
-  try {  
-    parse_annot(data, start_index, end_index);
-  } catch(annotation_load_error e) {
-    std::ostringstream msg;
-    msg << file_path.native_file_string()
-        << " "
-        << e.what();
-    throw annotation_load_error(msg.str());
-  }
+  parse_annot(data, start_index, end_index);
 }
 
 /* If this works, yikes, this is some brain hurting code.
@@ -432,16 +423,32 @@ struct push_back_seq {
   void operator()(std::string::const_iterator, 
                   std::string::const_iterator) const 
   {
+    std::string::iterator seq_i = seq.begin();
+    std::string::iterator seq_end = seq.end();
+
+    // this if block is a hack, for some reason spirit was
+    // duplicating the last character if the file didn't end
+    // with a new line. 
+    // this checks for the trailing newline, and if it is missing
+    // removes the last character ( which should be the duplicated character. 
+    // check test_sequence.cpp:sequence_no_trailing_newline for test case
+    // also see ticket:265 for more information
+    if (seq.size() > 0) {
+      std::string::value_type c = seq[seq.size()-1];
+      if (not (c == '\015' or c == '\012')) {
+        // doesn't end with a new line character
+        seq_end--;
+      }
+    }
+    // end hack
+
     // filter out newlines from our sequence
     std::string new_seq;
-    for(std::string::const_iterator seq_i = seq.begin();
-        seq_i != seq.end();
-        ++seq_i)
+    for(; seq_i != seq_end; ++seq_i)
     {
       if (*seq_i != '\015' && *seq_i != '\012') new_seq += *seq_i;
     }
     //std::cout << "adding seq: " << name << " " << new_seq << std::endl;
-    
     Sequence s(new_seq);
     s.set_fasta_header(name);
     seq_list.push_back(s);
@@ -686,11 +693,6 @@ Sequence::save(fs::fstream &save_file)
   SeqSpanRefList::iterator annots_i;
   AnnotationsRef metadata;
 
-  // not sure why, or if i'm doing something wrong, but can't seem to pass
-  // file pointers down to this method from the mussa control class
-  // so each call to save a sequence appends to the file started by mussa_class
-  //save_file.open(save_file_path.c_str(), std::ios::app);
-
   save_file << "<Sequence>" << std::endl;
   save_file << *this << std::endl;
   save_file << "</Sequence>" << std::endl;