From 2c7a6a7a64bf6ce5920dff2446ffb9a21cac02ef Mon Sep 17 00:00:00 2001
From: Marco Biasini <marco.biasini@unibas.ch>
Date: Tue, 12 Jul 2011 15:35:22 +0200
Subject: [PATCH] introduce FormatDiagnostic routine

---
 modules/io/src/mol/star_parser.cc    | 45 +++++++++++++++++++++++-----
 modules/io/src/mol/star_parser.hh    | 16 +++++++++-
 modules/io/tests/test_star_parser.cc | 28 +++++++++++++++++
 3 files changed, 81 insertions(+), 8 deletions(-)

diff --git a/modules/io/src/mol/star_parser.cc b/modules/io/src/mol/star_parser.cc
index d21d00278..b440181c9 100644
--- a/modules/io/src/mol/star_parser.cc
+++ b/modules/io/src/mol/star_parser.cc
@@ -28,12 +28,45 @@
 namespace ost { namespace io {
 
 StarParser::StarParser(std::istream& stream, bool items_as_row):
-  stream_(stream), line_num_(0), has_current_line_(false), current_line_(),
+  stream_(stream), filename_("<stream>"), line_num_(0),
+  has_current_line_(false), current_line_(),
+  items_row_header_(), items_row_columns_(),
+  items_row_values_()
+{
+  items_as_row_ = items_as_row;
+}
+
+StarParser::StarParser(const String& filename, bool items_as_row):
+  fstream_(filename.c_str()), stream_(fstream_), filename_(filename),
+  line_num_(0), has_current_line_(false), current_line_(),
   items_row_header_(), items_row_columns_(), items_row_values_()
 {
   items_as_row_ = items_as_row;
 }
 
+String StarParser::FormatDiagnostic(StarDiagType type, const String& message,
+                                    int line)
+{
+  std::stringstream ss;
+  ss << filename_ << ":";
+  if (line!=-1) {
+    ss << line << ": ";
+  } else {
+    ss << " ";
+  }
+  switch (type) {
+    case STAR_DIAG_ERROR:
+      ss << "error: ";
+      break;
+    case STAR_DIAG_WARNING:
+      ss << "warning: ";
+      break;
+  }
+  ss << message;
+  return ss.str();
+}
+
+
 bool StarParser::SplitLine(const StringRef& line, 
                             std::vector<StringRef>& parts, bool clear)
 {
@@ -363,10 +396,9 @@ void StarParser::DiagnoseUnknown()
   StringRef line;
   bool r=this->GetLine(line);
   assert(r);r=r;
-  
-  ss << "unknown control structure '"<< line.rtrim() << "' on line " 
-     << line_num_ << "." << std::endl;
-  throw IOException(ss.str());
+  ss << "unknown control structure '"<< line.rtrim() << "'";
+  throw IOException(this->FormatDiagnostic(STAR_DIAG_ERROR, ss.str(),
+                                           line_num_));
 }
 
 void StarParser::ParseGlobal()
@@ -400,8 +432,7 @@ void StarParser::Parse()
         this->ConsumeLine();
         break;
       default:
-        ss << "Missing 'data_' control structure." << std::endl;
-        throw IOException(ss.str());
+        throw IOException("Missing 'data_' control structure");
         break;
     }
   }
diff --git a/modules/io/src/mol/star_parser.hh b/modules/io/src/mol/star_parser.hh
index 47aa98b0e..e151e6c09 100644
--- a/modules/io/src/mol/star_parser.hh
+++ b/modules/io/src/mol/star_parser.hh
@@ -24,6 +24,7 @@
   Author: Marco Biasini
  */
 #include <iostream>
+#include <fstream>
 #include <vector>
 #include <map>
 #include <ost/string_ref.hh>
@@ -31,6 +32,13 @@
 
 namespace ost { namespace io {
 
+
+typedef enum {
+  STAR_DIAG_WARNING,
+  STAR_DIAG_ERROR
+} StarDiagType;
+
+
 class DLLEXPORT_OST_IO StarDataItem {
 public:
   StarDataItem(const StringRef& category, const StringRef& name, 
@@ -108,7 +116,7 @@ public:
   ///                    header, values as row) and then parsed like a loop
   ///                    (OnBeginLoop(), OnDataRow(), OnEndLoop())
   explicit StarParser(std::istream& stream, bool items_as_row=false);
-
+  explicit StarParser(const String& filename, bool items_as_row=false);
   virtual ~StarParser() { }
 // callback interface
 public:
@@ -139,6 +147,10 @@ public:
   /// \brief called when leaving a datasection. Will only be invoked when 
   ///     OnBeginData() returned true.
   virtual void OnEndData() { }
+
+  /// \brief format diagnostic and returns it as a string.
+  String FormatDiagnostic(StarDiagType type, const String& message,
+                          int line=-1);
 public:
   void Parse();
   
@@ -187,7 +199,9 @@ private:
   void ParseDataItem();
   void DiagnoseUnknown();
   bool ParseMultilineValue(String& value, bool skip=false);
+  std::ifstream fstream_;
   std::istream& stream_;
+  String        filename_;
   int           line_num_;
   bool          has_current_line_;
   String        current_line_;
diff --git a/modules/io/tests/test_star_parser.cc b/modules/io/tests/test_star_parser.cc
index fc58a63b6..67a818fc2 100644
--- a/modules/io/tests/test_star_parser.cc
+++ b/modules/io/tests/test_star_parser.cc
@@ -37,6 +37,9 @@ class DataItemTestParser: public StarParser {
 public:
   DataItemTestParser(std::istream& stream): StarParser(stream)
   { }
+
+  DataItemTestParser(const String& filename): StarParser(filename)
+  { }
   virtual void OnDataItem(const StarDataItem& item)
   {
     BOOST_CHECK_EQUAL(item.GetCategory().str(), "data-item");
@@ -242,6 +245,31 @@ BOOST_AUTO_TEST_CASE(star_data_item)
   BOOST_CHECK_EQUAL(star_p.s4, "a'b");
 }
 
+BOOST_AUTO_TEST_CASE(format_diag_stream)
+{
+  BOOST_MESSAGE("  Running star_data_item tests...");
+  std::ifstream s("testfiles/data-item.cif");
+  DataItemTestParser star_p(s);
+  BOOST_CHECK_EQUAL(star_p.FormatDiagnostic(STAR_DIAG_WARNING, "bad", -1),
+                    "<stream>: warning: bad");
+  BOOST_CHECK_EQUAL(star_p.FormatDiagnostic(STAR_DIAG_ERROR, "really bad", -1),
+                    "<stream>: error: really bad");
+  BOOST_CHECK_EQUAL(star_p.FormatDiagnostic(STAR_DIAG_ERROR, "bad", 55),
+                    "<stream>:55: error: bad");
+}
+
+BOOST_AUTO_TEST_CASE(format_diag_filename)
+{
+  BOOST_MESSAGE("  Running star_data_item tests...");
+  DataItemTestParser star_p("testfiles/data-item.cif");
+  BOOST_CHECK_EQUAL(star_p.FormatDiagnostic(STAR_DIAG_WARNING, "bad", -1),
+                    "testfiles/data-item.cif: warning: bad");
+  BOOST_CHECK_EQUAL(star_p.FormatDiagnostic(STAR_DIAG_ERROR, "really bad", -1),
+                    "testfiles/data-item.cif: error: really bad");
+  BOOST_CHECK_EQUAL(star_p.FormatDiagnostic(STAR_DIAG_ERROR, "bad", 55),
+                    "testfiles/data-item.cif:55: error: bad");
+}
+
 BOOST_AUTO_TEST_CASE(star_multi)
 {
   std::ifstream s("testfiles/multi-data.cif");
-- 
GitLab