lemon/lgf_reader.h
changeset 189 a63ed81c57ba
parent 188 70694e6bdcac
child 190 1e6af6f0843c
equal deleted inserted replaced
16:dede6b043875 17:c60f07796eb9
   417   ///\endcode
   417   ///\endcode
   418   ///
   418   ///
   419   /// By default the reader uses the first section in the file of the
   419   /// By default the reader uses the first section in the file of the
   420   /// proper type. If a section has an optional name, then it can be
   420   /// proper type. If a section has an optional name, then it can be
   421   /// selected for reading by giving an optional name parameter to the
   421   /// selected for reading by giving an optional name parameter to the
   422   /// \c nodes(), \c arcs() or \c attributes() functions. The readers
   422   /// \c nodes(), \c arcs() or \c attributes() functions.
   423   /// also can load extra sections with the \c sectionLines() and
       
   424   /// sectionStream() functions.
       
   425   ///
   423   ///
   426   /// The \c useNodes() and \c useArcs() functions are used to tell the reader
   424   /// The \c useNodes() and \c useArcs() functions are used to tell the reader
   427   /// that the nodes or arcs should not be constructed (added to the
   425   /// that the nodes or arcs should not be constructed (added to the
   428   /// graph) during the reading, but instead the label map of the items
   426   /// graph) during the reading, but instead the label map of the items
   429   /// are given as a parameter of these functions. An
   427   /// are given as a parameter of these functions. An
   471 
   469 
   472     typedef std::multimap<std::string, _reader_bits::ValueStorageBase*> 
   470     typedef std::multimap<std::string, _reader_bits::ValueStorageBase*> 
   473       Attributes;
   471       Attributes;
   474     Attributes _attributes;
   472     Attributes _attributes;
   475 
   473 
   476     typedef std::map<std::string, _reader_bits::Section*> Sections;
       
   477     Sections _sections;
       
   478 
       
   479     bool _use_nodes;
   474     bool _use_nodes;
   480     bool _use_arcs;
   475     bool _use_arcs;
   481 
   476 
   482     bool _skip_nodes;
   477     bool _skip_nodes;
   483     bool _skip_arcs;
   478     bool _skip_arcs;
   535 
   530 
   536       _nodes_caption = other._nodes_caption;
   531       _nodes_caption = other._nodes_caption;
   537       _arcs_caption = other._arcs_caption;
   532       _arcs_caption = other._arcs_caption;
   538       _attributes_caption = other._attributes_caption;
   533       _attributes_caption = other._attributes_caption;
   539 
   534 
   540       _sections.swap(other._sections);
       
   541     }
   535     }
   542 
   536 
   543     /// \brief Destructor
   537     /// \brief Destructor
   544     ~DigraphReader() {
   538     ~DigraphReader() {
   545       for (typename NodeMaps::iterator it = _node_maps.begin(); 
   539       for (typename NodeMaps::iterator it = _node_maps.begin(); 
   552 	delete it->second;
   546 	delete it->second;
   553       }
   547       }
   554 
   548 
   555       for (typename Attributes::iterator it = _attributes.begin(); 
   549       for (typename Attributes::iterator it = _attributes.begin(); 
   556 	   it != _attributes.end(); ++it) {
   550 	   it != _attributes.end(); ++it) {
   557 	delete it->second;
       
   558       }
       
   559 
       
   560       for (typename Sections::iterator it = _sections.begin(); 
       
   561 	   it != _sections.end(); ++it) {
       
   562 	delete it->second;
   551 	delete it->second;
   563       }
   552       }
   564 
   553 
   565       if (local_is) {
   554       if (local_is) {
   566 	delete _is;
   555 	delete _is;
   704     DigraphReader& attributes(const std::string& caption) {
   693     DigraphReader& attributes(const std::string& caption) {
   705       _attributes_caption = caption;
   694       _attributes_caption = caption;
   706       return *this;
   695       return *this;
   707     }
   696     }
   708 
   697 
   709     /// @}
       
   710 
       
   711     /// \name Section readers
       
   712     /// @{
       
   713 
       
   714     /// \brief Add a section processor with line oriented reading
       
   715     ///
       
   716     /// In the \e LGF file extra sections can be placed, which contain
       
   717     /// any data in arbitrary format. These sections can be read with
       
   718     /// this function line by line. The first parameter is the type
       
   719     /// descriptor of the section, the second is a functor, which
       
   720     /// takes just one \c std::string parameter. At the reading
       
   721     /// process, each line of the section will be given to the functor
       
   722     /// object. However, the empty lines and the comment lines are
       
   723     /// filtered out, and the leading whitespaces are stipped from
       
   724     /// each processed string.
       
   725     ///
       
   726     /// For example let's see a section, which contain several
       
   727     /// integers, which should be inserted into a vector.
       
   728     ///\code
       
   729     ///  @numbers
       
   730     ///  12 45 23
       
   731     ///  4
       
   732     ///  23 6
       
   733     ///\endcode
       
   734     ///
       
   735     /// The functor is implemented as an struct:
       
   736     ///\code
       
   737     ///  struct NumberSection {
       
   738     ///    std::vector<int>& _data;
       
   739     ///    NumberSection(std::vector<int>& data) : _data(data) {}
       
   740     ///    void operator()(const std::string& line) {
       
   741     ///      std::istringstream ls(line);
       
   742     ///      int value;
       
   743     ///      while (ls >> value) _data.push_back(value);
       
   744     ///    }
       
   745     ///  };
       
   746     ///
       
   747     ///  // ...
       
   748     ///
       
   749     ///  reader.sectionLines("numbers", NumberSection(vec));  
       
   750     ///\endcode
       
   751     template <typename Functor>
       
   752     DigraphReader& sectionLines(const std::string& type, Functor functor) {
       
   753       LEMON_ASSERT(!type.empty(), "Type is not empty.");
       
   754       LEMON_ASSERT(_sections.find(type) == _sections.end(), 
       
   755 		   "Multiple reading of section.");
       
   756       LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" &&
       
   757 		   type != "attributes", "Multiple reading of section.");
       
   758       _sections.insert(std::make_pair(type, 
       
   759         new _reader_bits::LineSection<Functor>(functor)));
       
   760       return *this;
       
   761     }
       
   762 
       
   763 
       
   764     /// \brief Add a section processor with stream oriented reading
       
   765     ///
       
   766     /// In the \e LGF file extra sections can be placed, which contain
       
   767     /// any data in arbitrary format. These sections can be read
       
   768     /// directly with this function. The first parameter is the type
       
   769     /// of the section, the second is a functor, which takes an \c
       
   770     /// std::istream& and an int& parameter, the latter regard to the
       
   771     /// line number of stream. The functor can read the input while
       
   772     /// the section go on, and the line number should be modified
       
   773     /// accordingly.
       
   774     template <typename Functor>
       
   775     DigraphReader& sectionStream(const std::string& type, Functor functor) {
       
   776       LEMON_ASSERT(!type.empty(), "Type is not empty.");
       
   777       LEMON_ASSERT(_sections.find(type) == _sections.end(), 
       
   778 		   "Multiple reading of section.");
       
   779       LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" &&
       
   780 		   type != "attributes", "Multiple reading of section.");
       
   781       _sections.insert(std::make_pair(type, 
       
   782 	 new _reader_bits::StreamSection<Functor>(functor)));
       
   783       return *this;
       
   784     }    
       
   785     
       
   786     /// @}
   698     /// @}
   787 
   699 
   788     /// \name Using previously constructed node or arc set
   700     /// \name Using previously constructed node or arc set
   789     /// @{
   701     /// @{
   790 
   702 
  1186       }
  1098       }
  1187       
  1099       
  1188       bool nodes_done = _skip_nodes;
  1100       bool nodes_done = _skip_nodes;
  1189       bool arcs_done = _skip_arcs;
  1101       bool arcs_done = _skip_arcs;
  1190       bool attributes_done = false;
  1102       bool attributes_done = false;
  1191       std::set<std::string> extra_sections;
       
  1192 
  1103 
  1193       line_num = 0;      
  1104       line_num = 0;      
  1194       readLine();
  1105       readLine();
  1195       skipSection();
  1106       skipSection();
  1196 
  1107 
  1220 	    if (_attributes_caption.empty() || _attributes_caption == caption) {
  1131 	    if (_attributes_caption.empty() || _attributes_caption == caption) {
  1221 	      readAttributes();
  1132 	      readAttributes();
  1222 	      attributes_done = true;
  1133 	      attributes_done = true;
  1223 	    }
  1134 	    }
  1224 	  } else {
  1135 	  } else {
  1225 	    if (extra_sections.find(section) != extra_sections.end()) {
       
  1226 	      std::ostringstream msg;
       
  1227 	      msg << "Multiple occurence of section " << section;
       
  1228 	      throw DataFormatError(msg.str().c_str());
       
  1229 	    }
       
  1230 	    Sections::iterator it = _sections.find(section);
       
  1231 	    if (it != _sections.end()) {
       
  1232 	      extra_sections.insert(section);
       
  1233 	      it->second->process(*_is, line_num);
       
  1234 	    }
       
  1235 	    readLine();
  1136 	    readLine();
  1236 	    skipSection();
  1137 	    skipSection();
  1237 	  }
  1138 	  }
  1238 	} catch (DataFormatError& error) {
  1139 	} catch (DataFormatError& error) {
  1239 	  error.line(line_num);
  1140 	  error.line(line_num);
  1293     typedef _Graph Graph;
  1194     typedef _Graph Graph;
  1294     TEMPLATE_GRAPH_TYPEDEFS(Graph);
  1195     TEMPLATE_GRAPH_TYPEDEFS(Graph);
  1295     
  1196     
  1296   private:
  1197   private:
  1297 
  1198 
  1298 
       
  1299     std::istream* _is;
  1199     std::istream* _is;
  1300     bool local_is;
  1200     bool local_is;
  1301 
  1201 
  1302     Graph& _graph;
  1202     Graph& _graph;
  1303 
  1203 
  1319     EdgeMaps _edge_maps;
  1219     EdgeMaps _edge_maps;
  1320 
  1220 
  1321     typedef std::multimap<std::string, _reader_bits::ValueStorageBase*> 
  1221     typedef std::multimap<std::string, _reader_bits::ValueStorageBase*> 
  1322       Attributes;
  1222       Attributes;
  1323     Attributes _attributes;
  1223     Attributes _attributes;
  1324 
       
  1325     typedef std::map<std::string, _reader_bits::Section*> Sections;
       
  1326     Sections _sections;
       
  1327 
  1224 
  1328     bool _use_nodes;
  1225     bool _use_nodes;
  1329     bool _use_edges;
  1226     bool _use_edges;
  1330 
  1227 
  1331     bool _skip_nodes;
  1228     bool _skip_nodes;
  1384 
  1281 
  1385       _nodes_caption = other._nodes_caption;
  1282       _nodes_caption = other._nodes_caption;
  1386       _edges_caption = other._edges_caption;
  1283       _edges_caption = other._edges_caption;
  1387       _attributes_caption = other._attributes_caption;
  1284       _attributes_caption = other._attributes_caption;
  1388 
  1285 
  1389       _sections.swap(other._sections);
       
  1390     }
  1286     }
  1391 
  1287 
  1392     /// \brief Destructor
  1288     /// \brief Destructor
  1393     ~GraphReader() {
  1289     ~GraphReader() {
  1394       for (typename NodeMaps::iterator it = _node_maps.begin(); 
  1290       for (typename NodeMaps::iterator it = _node_maps.begin(); 
  1401 	delete it->second;
  1297 	delete it->second;
  1402       }
  1298       }
  1403 
  1299 
  1404       for (typename Attributes::iterator it = _attributes.begin(); 
  1300       for (typename Attributes::iterator it = _attributes.begin(); 
  1405 	   it != _attributes.end(); ++it) {
  1301 	   it != _attributes.end(); ++it) {
  1406 	delete it->second;
       
  1407       }
       
  1408 
       
  1409       for (typename Sections::iterator it = _sections.begin(); 
       
  1410 	   it != _sections.end(); ++it) {
       
  1411 	delete it->second;
  1302 	delete it->second;
  1412       }
  1303       }
  1413 
  1304 
  1414       if (local_is) {
  1305       if (local_is) {
  1415 	delete _is;
  1306 	delete _is;
  1599     GraphReader& attributes(const std::string& caption) {
  1490     GraphReader& attributes(const std::string& caption) {
  1600       _attributes_caption = caption;
  1491       _attributes_caption = caption;
  1601       return *this;
  1492       return *this;
  1602     }
  1493     }
  1603 
  1494 
  1604     /// @}
       
  1605 
       
  1606     /// \name Section readers
       
  1607     /// @{
       
  1608 
       
  1609     /// \brief Add a section processor with line oriented reading
       
  1610     ///
       
  1611     /// In the \e LGF file extra sections can be placed, which contain
       
  1612     /// any data in arbitrary format. These sections can be read with
       
  1613     /// this function line by line. The first parameter is the type
       
  1614     /// descriptor of the section, the second is a functor, which
       
  1615     /// takes just one \c std::string parameter. At the reading
       
  1616     /// process, each line of the section will be given to the functor
       
  1617     /// object. However, the empty lines and the comment lines are
       
  1618     /// filtered out, and the leading whitespaces are stipped from
       
  1619     /// each processed string.
       
  1620     ///
       
  1621     /// For example let's see a section, which contain several
       
  1622     /// integers, which should be inserted into a vector.
       
  1623     ///\code
       
  1624     ///  @numbers
       
  1625     ///  12 45 23
       
  1626     ///  4
       
  1627     ///  23 6
       
  1628     ///\endcode
       
  1629     ///
       
  1630     /// The functor is implemented as an struct:
       
  1631     ///\code
       
  1632     ///  struct NumberSection {
       
  1633     ///    std::vector<int>& _data;
       
  1634     ///    NumberSection(std::vector<int>& data) : _data(data) {}
       
  1635     ///    void operator()(const std::string& line) {
       
  1636     ///      std::istringstream ls(line);
       
  1637     ///      int value;
       
  1638     ///      while (ls >> value) _data.push_back(value);
       
  1639     ///    }
       
  1640     ///  };
       
  1641     ///
       
  1642     ///  // ...
       
  1643     ///
       
  1644     ///  reader.sectionLines("numbers", NumberSection(vec));  
       
  1645     ///\endcode
       
  1646     template <typename Functor>
       
  1647     GraphReader& sectionLines(const std::string& type, Functor functor) {
       
  1648       LEMON_ASSERT(!type.empty(), "Type is not empty.");
       
  1649       LEMON_ASSERT(_sections.find(type) == _sections.end(), 
       
  1650 		   "Multiple reading of section.");
       
  1651       LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" &&
       
  1652 		   type != "attributes", "Multiple reading of section.");
       
  1653       _sections.insert(std::make_pair(type, 
       
  1654         new _reader_bits::LineSection<Functor>(functor)));
       
  1655       return *this;
       
  1656     }
       
  1657 
       
  1658 
       
  1659     /// \brief Add a section processor with stream oriented reading
       
  1660     ///
       
  1661     /// In the \e LGF file extra sections can be placed, which contain
       
  1662     /// any data in arbitrary format. These sections can be read
       
  1663     /// directly with this function. The first parameter is the type
       
  1664     /// of the section, the second is a functor, which takes an \c
       
  1665     /// std::istream& and an int& parameter, the latter regard to the
       
  1666     /// line number of stream. The functor can read the input while
       
  1667     /// the section go on, and the line number should be modified
       
  1668     /// accordingly.
       
  1669     template <typename Functor>
       
  1670     GraphReader& sectionStream(const std::string& type, Functor functor) {
       
  1671       LEMON_ASSERT(!type.empty(), "Type is not empty.");
       
  1672       LEMON_ASSERT(_sections.find(type) == _sections.end(), 
       
  1673 		   "Multiple reading of section.");
       
  1674       LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" &&
       
  1675 		   type != "attributes", "Multiple reading of section.");
       
  1676       _sections.insert(std::make_pair(type, 
       
  1677 	 new _reader_bits::StreamSection<Functor>(functor)));
       
  1678       return *this;
       
  1679     }    
       
  1680     
       
  1681     /// @}
  1495     /// @}
  1682 
  1496 
  1683     /// \name Using previously constructed node or edge set
  1497     /// \name Using previously constructed node or edge set
  1684     /// @{
  1498     /// @{
  1685 
  1499 
  2079       LEMON_ASSERT(_is != 0, "This reader assigned to an other reader");
  1893       LEMON_ASSERT(_is != 0, "This reader assigned to an other reader");
  2080       
  1894       
  2081       bool nodes_done = _skip_nodes;
  1895       bool nodes_done = _skip_nodes;
  2082       bool edges_done = _skip_edges;
  1896       bool edges_done = _skip_edges;
  2083       bool attributes_done = false;
  1897       bool attributes_done = false;
  2084       std::set<std::string> extra_sections;
       
  2085 
  1898 
  2086       line_num = 0;      
  1899       line_num = 0;      
  2087       readLine();
  1900       readLine();
  2088       skipSection();
  1901       skipSection();
  2089 
  1902 
  2113 	    if (_attributes_caption.empty() || _attributes_caption == caption) {
  1926 	    if (_attributes_caption.empty() || _attributes_caption == caption) {
  2114 	      readAttributes();
  1927 	      readAttributes();
  2115 	      attributes_done = true;
  1928 	      attributes_done = true;
  2116 	    }
  1929 	    }
  2117 	  } else {
  1930 	  } else {
  2118 	    if (extra_sections.find(section) != extra_sections.end()) {
       
  2119 	      std::ostringstream msg;
       
  2120 	      msg << "Multiple occurence of section " << section;
       
  2121 	      throw DataFormatError(msg.str().c_str());
       
  2122 	    }
       
  2123 	    Sections::iterator it = _sections.find(section);
       
  2124 	    if (it != _sections.end()) {
       
  2125 	      extra_sections.insert(section);
       
  2126 	      it->second->process(*_is, line_num);
       
  2127 	    }
       
  2128 	    readLine();
  1931 	    readLine();
  2129 	    skipSection();
  1932 	    skipSection();
  2130 	  }
  1933 	  }
  2131 	} catch (DataFormatError& error) {
  1934 	} catch (DataFormatError& error) {
  2132 	  error.line(line_num);
  1935 	  error.line(line_num);
  2169 
  1972 
  2170   /// \relates GraphReader
  1973   /// \relates GraphReader
  2171   template <typename Graph>
  1974   template <typename Graph>
  2172   GraphReader<Graph> graphReader(const char* fn, Graph& graph) {
  1975   GraphReader<Graph> graphReader(const char* fn, Graph& graph) {
  2173     GraphReader<Graph> tmp(fn, graph);
  1976     GraphReader<Graph> tmp(fn, graph);
       
  1977     return tmp;
       
  1978   }
       
  1979 
       
  1980   /// \brief Section reader class
       
  1981   ///
       
  1982   /// In the \e LGF file extra sections can be placed, which contain
       
  1983   /// any data in arbitrary format. Such sections can be read with
       
  1984   /// this class. A reading rule can be added with two different
       
  1985   /// functions, with the \c sectionLines() function a functor can
       
  1986   /// process the section line-by-line. While with the \c
       
  1987   /// sectionStream() member the section can be read from an input
       
  1988   /// stream.
       
  1989   class SectionReader {
       
  1990   private:
       
  1991     
       
  1992     std::istream* _is;
       
  1993     bool local_is;
       
  1994 
       
  1995     typedef std::map<std::string, _reader_bits::Section*> Sections;
       
  1996     Sections _sections;
       
  1997 
       
  1998     int line_num;
       
  1999     std::istringstream line;
       
  2000 
       
  2001   public:
       
  2002 
       
  2003     /// \brief Constructor
       
  2004     ///
       
  2005     /// Construct a section reader, which reads from the given input
       
  2006     /// stream.
       
  2007     SectionReader(std::istream& is) 
       
  2008       : _is(&is), local_is(false) {}
       
  2009 
       
  2010     /// \brief Constructor
       
  2011     ///
       
  2012     /// Construct a section reader, which reads from the given file.
       
  2013     SectionReader(const std::string& fn) 
       
  2014       : _is(new std::ifstream(fn.c_str())), local_is(true) {}
       
  2015     
       
  2016     /// \brief Constructor
       
  2017     ///
       
  2018     /// Construct a section reader, which reads from the given file.
       
  2019     SectionReader(const char* fn) 
       
  2020       : _is(new std::ifstream(fn)), local_is(true) {}
       
  2021 
       
  2022     /// \brief Copy constructor
       
  2023     ///
       
  2024     /// The copy constructor transfers all data from the other reader,
       
  2025     /// therefore the copied reader will not be usable more. 
       
  2026     SectionReader(SectionReader& other) 
       
  2027       : _is(other._is), local_is(other.local_is) {
       
  2028 
       
  2029       other._is = 0;
       
  2030       other.local_is = false;
       
  2031       
       
  2032       _sections.swap(other._sections);
       
  2033     }
       
  2034 
       
  2035     /// \brief Destructor
       
  2036     ~SectionReader() {
       
  2037       for (Sections::iterator it = _sections.begin(); 
       
  2038 	   it != _sections.end(); ++it) {
       
  2039 	delete it->second;
       
  2040       }
       
  2041 
       
  2042       if (local_is) {
       
  2043 	delete _is;
       
  2044       }
       
  2045 
       
  2046     }
       
  2047 
       
  2048   private:
       
  2049     
       
  2050     SectionReader& operator=(const SectionReader&);
       
  2051 
       
  2052   public:
       
  2053 
       
  2054     /// \name Section readers
       
  2055     /// @{
       
  2056 
       
  2057     /// \brief Add a section processor with line oriented reading
       
  2058     ///
       
  2059     /// The first parameter is the type descriptor of the section, the
       
  2060     /// second is a functor, which takes just one \c std::string
       
  2061     /// parameter. At the reading process, each line of the section
       
  2062     /// will be given to the functor object. However, the empty lines
       
  2063     /// and the comment lines are filtered out, and the leading
       
  2064     /// whitespaces are trimmed from each processed string.
       
  2065     ///
       
  2066     /// For example let's see a section, which contain several
       
  2067     /// integers, which should be inserted into a vector.
       
  2068     ///\code
       
  2069     ///  @numbers
       
  2070     ///  12 45 23
       
  2071     ///  4
       
  2072     ///  23 6
       
  2073     ///\endcode
       
  2074     ///
       
  2075     /// The functor is implemented as an struct:
       
  2076     ///\code
       
  2077     ///  struct NumberSection {
       
  2078     ///    std::vector<int>& _data;
       
  2079     ///    NumberSection(std::vector<int>& data) : _data(data) {}
       
  2080     ///    void operator()(const std::string& line) {
       
  2081     ///      std::istringstream ls(line);
       
  2082     ///      int value;
       
  2083     ///      while (ls >> value) _data.push_back(value);
       
  2084     ///    }
       
  2085     ///  };
       
  2086     ///
       
  2087     ///  // ...
       
  2088     ///
       
  2089     ///  reader.sectionLines("numbers", NumberSection(vec));  
       
  2090     ///\endcode
       
  2091     template <typename Functor>
       
  2092     SectionReader& sectionLines(const std::string& type, Functor functor) {
       
  2093       LEMON_ASSERT(!type.empty(), "Type is not empty.");
       
  2094       LEMON_ASSERT(_sections.find(type) == _sections.end(), 
       
  2095 		   "Multiple reading of section.");
       
  2096       _sections.insert(std::make_pair(type, 
       
  2097         new _reader_bits::LineSection<Functor>(functor)));
       
  2098       return *this;
       
  2099     }
       
  2100 
       
  2101 
       
  2102     /// \brief Add a section processor with stream oriented reading
       
  2103     ///
       
  2104     /// The first parameter is the type of the section, the second is
       
  2105     /// a functor, which takes an \c std::istream& and an int&
       
  2106     /// parameter, the latter regard to the line number of stream. The
       
  2107     /// functor can read the input while the section go on, and the
       
  2108     /// line number should be modified accordingly.
       
  2109     template <typename Functor>
       
  2110     SectionReader& sectionStream(const std::string& type, Functor functor) {
       
  2111       LEMON_ASSERT(!type.empty(), "Type is not empty.");
       
  2112       LEMON_ASSERT(_sections.find(type) == _sections.end(), 
       
  2113 		   "Multiple reading of section.");
       
  2114       _sections.insert(std::make_pair(type, 
       
  2115 	 new _reader_bits::StreamSection<Functor>(functor)));
       
  2116       return *this;
       
  2117     }    
       
  2118     
       
  2119     /// @}
       
  2120 
       
  2121   private:
       
  2122 
       
  2123     bool readLine() {
       
  2124       std::string str;
       
  2125       while(++line_num, std::getline(*_is, str)) {
       
  2126 	line.clear(); line.str(str);
       
  2127 	char c;
       
  2128 	if (line >> std::ws >> c && c != '#') {
       
  2129 	  line.putback(c);
       
  2130 	  return true;
       
  2131 	}
       
  2132       }
       
  2133       return false;
       
  2134     }
       
  2135 
       
  2136     bool readSuccess() {
       
  2137       return static_cast<bool>(*_is);
       
  2138     }
       
  2139     
       
  2140     void skipSection() {
       
  2141       char c;
       
  2142       while (readSuccess() && line >> c && c != '@') {
       
  2143 	readLine();
       
  2144       }
       
  2145       line.putback(c);
       
  2146     }
       
  2147 
       
  2148   public:
       
  2149 
       
  2150 
       
  2151     /// \name Execution of the reader    
       
  2152     /// @{
       
  2153 
       
  2154     /// \brief Start the batch processing
       
  2155     ///
       
  2156     /// This function starts the batch processing
       
  2157     void run() {
       
  2158       
       
  2159       LEMON_ASSERT(_is != 0, "This reader assigned to an other reader");
       
  2160       
       
  2161       std::set<std::string> extra_sections;
       
  2162 
       
  2163       line_num = 0;      
       
  2164       readLine();
       
  2165       skipSection();
       
  2166 
       
  2167       while (readSuccess()) {
       
  2168 	try {
       
  2169 	  char c;
       
  2170 	  std::string section, caption;
       
  2171 	  line >> c;
       
  2172 	  _reader_bits::readToken(line, section);
       
  2173 	  _reader_bits::readToken(line, caption);
       
  2174 
       
  2175 	  if (line >> c) 
       
  2176 	    throw DataFormatError("Extra character on the end of line");
       
  2177 
       
  2178 	  if (extra_sections.find(section) != extra_sections.end()) {
       
  2179 	    std::ostringstream msg;
       
  2180 	    msg << "Multiple occurence of section " << section;
       
  2181 	    throw DataFormatError(msg.str().c_str());
       
  2182 	  }
       
  2183 	  Sections::iterator it = _sections.find(section);
       
  2184 	  if (it != _sections.end()) {
       
  2185 	    extra_sections.insert(section);
       
  2186 	    it->second->process(*_is, line_num);
       
  2187 	  }
       
  2188 	  readLine();
       
  2189 	  skipSection();
       
  2190 	} catch (DataFormatError& error) {
       
  2191 	  error.line(line_num);
       
  2192 	  throw;
       
  2193 	}	
       
  2194       }
       
  2195       for (Sections::iterator it = _sections.begin();
       
  2196 	   it != _sections.end(); ++it) {
       
  2197 	if (extra_sections.find(it->first) == extra_sections.end()) {
       
  2198 	  std::ostringstream os;
       
  2199 	  os << "Cannot find section: " << it->first;
       
  2200 	  throw DataFormatError(os.str().c_str());
       
  2201 	}
       
  2202       }
       
  2203     }
       
  2204 
       
  2205     /// @}
       
  2206         
       
  2207   };
       
  2208 
       
  2209   /// \relates SectionReader
       
  2210   inline SectionReader sectionReader(std::istream& is) {
       
  2211     SectionReader tmp(is);
       
  2212     return tmp;
       
  2213   }
       
  2214 
       
  2215   /// \relates SectionReader
       
  2216   inline SectionReader sectionReader(const std::string& fn) {
       
  2217     SectionReader tmp(fn);
       
  2218     return tmp;
       
  2219   }
       
  2220 
       
  2221   /// \relates SectionReader
       
  2222   inline SectionReader sectionReader(const char* fn) {
       
  2223     SectionReader tmp(fn);
  2174     return tmp;
  2224     return tmp;
  2175   }
  2225   }
  2176 
  2226 
  2177   /// \ingroup lemon_io
  2227   /// \ingroup lemon_io
  2178   ///
  2228   ///