Index: src/lemon/Makefile.am
===================================================================
--- src/lemon/Makefile.am	(revision 1402)
+++ src/lemon/Makefile.am	(revision 1408)
@@ -53,4 +53,5 @@
 	concept_check.h \
 	utility.h \
+	lemon_reader.h \
 	graph_reader.h \
 	graph_writer.h \
@@ -65,5 +66,6 @@
 	bits/clearable_graph_extender.h \
 	bits/erasable_graph_extender.h \
-	bits/undir_graph_extender.h
+	bits/undir_graph_extender.h \
+	bits/item_reader.h
 
 noinst_HEADERS = \
Index: src/lemon/bits/item_reader.h
===================================================================
--- src/lemon/bits/item_reader.h	(revision 1408)
+++ src/lemon/bits/item_reader.h	(revision 1408)
@@ -0,0 +1,395 @@
+/* -*- C++ -*-
+ * src/lemon/bits/item_reader.h - Part of LEMON, a generic C++ optimization library
+ *
+ * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+/// \ingroup io_group
+/// \file
+/// \brief Item reader bits for lemon input.
+
+#ifndef LEMON_BITS_ITEM_READER_H
+#define LEMON_BITS_ITEM_READER_H
+
+#include <iostream>
+#include <string>
+
+#include <vector>
+#include <deque>
+#include <list>
+#include <set>
+
+namespace lemon {
+  
+  template <typename Value>
+  class DefaultReader;
+
+  /// \ingroup io_group
+  ///
+  /// \brief Reader class for quoted strings.
+  ///
+  /// Reader class for quoted strings. It can process the escape
+  /// sequences in the string.
+  ///
+  /// \author Balazs Dezso
+  class QuotedStringReader {
+  public:
+    /// \brief The value type of reader.
+    ///
+    /// The value type of reader.
+    typedef std::string Value;
+    
+    /// \brief Constructor for the reader.
+    ///
+    /// Constructor for the reader. If the given parameter is true
+    /// the reader processes the escape sequences.
+    QuotedStringReader(bool _escaped = true) 
+      : escaped(_escaped) {}
+    
+    /// \brief Reads a quoted string from the given stream.
+    ///
+    /// Reads a quoted string from the given stream.
+    void read(std::istream& is, std::string& value) const {
+      char c;
+      value.clear();
+      is >> std::ws;
+      if (!is.get(c) || c != '\"') 
+	throw DataFormatError("Quoted string format error");
+      while (is.get(c) && c != '\"') {
+	if (escaped && c == '\\') {
+	  value += readEscape(is);
+	} else {
+	  value += c;
+	}
+      }
+      if (!is) throw DataFormatError("Quoted string format error");
+    }
+
+  private:
+    
+    static char readEscape(std::istream& is) {
+      char c;
+      switch (is.get(c), c) {
+      case '\\':
+	return '\\';
+      case '\"':
+	return '\"';
+      case '\'':
+	return '\'';
+      case '\?':
+	return '\?';
+      case 'a':
+	return '\a';
+      case 'b':
+	return '\b';
+      case 'f':
+	return '\f';
+      case 'n':
+	return '\n';
+      case 'r':
+	return '\r';
+      case 't':
+	return '\t';
+      case 'v':
+	return '\v';
+      case 'x':
+	{
+	  int code;
+	  if (!is.get(c) || !isHex(c)) 
+	    throw DataFormatError("Escape format error");
+	  else if (code = valueHex(c), !is.get(c) || !isHex(c)) is.putback(c);
+	  else code = code * 16 + valueHex(c);
+	  return code;
+	}
+      default:
+	{
+	  int code;
+	  if (!isOct(c)) 
+	    throw DataFormatError("Escape format error");
+	  else if (code = valueOct(c), !is.get(c) || !isOct(c)) 
+	    is.putback(c);
+	  else if (code = code * 8 + valueOct(c), !is.get(c) || !isOct(c)) 
+	    is.putback(c);
+	  else code = code * 8 + valueOct(c);
+	  return code;
+	}	      
+      } 
+    }
+
+    static bool isOct(char c) {
+      return '0' <= c && c <='7'; 
+    }
+    
+    static int valueOct(char c) {
+      return c - '0';
+    }
+
+   static bool isHex(char c) {
+      return ('0' <= c && c <= '9') || 
+	('a' <= c && c <= 'z') || 
+	('A' <= c && c <= 'Z'); 
+    }
+    
+    static int valueHex(char c) {
+      if ('0' <= c && c <= '9') return c - '0';
+      if ('a' <= c && c <= 'z') return c - 'a' + 10;
+      return c - 'A' + 10;
+    }
+
+    bool escaped;
+  };
+
+  /// \ingroup io_group
+  /// \brief Reader for standard containers.
+  ///
+  /// Reader for back insertable standard containers. The representation
+  /// of the container is the values enumerated between an open and a
+  /// close parse. 
+  ///
+  /// \author Balazs Dezso
+  template <
+    typename _Container, 
+    typename _ItemReader = DefaultReader<typename _Container::value_type> 
+  >
+  class PushBackReader {
+  public:
+    typedef _Container Value;
+    typedef _ItemReader ItemReader;
+
+  private:
+
+    ItemReader item_reader;
+
+  public:
+
+    /// \brief Reads the values into the container from the given stream.
+    ///
+    /// Reads the values into the container from the given stream.
+    void read(std::istream& is, Value& value) const {
+      char c;
+      if (!(is >> c) || c != '(') 
+	throw DataFormatError("PushBackReader format error");
+      while (is >> c && c != ')') {
+	is.putback(c);
+	typename ItemReader::Value item;
+	item_reader.read(is, item);
+	value.push_back(item);
+      }
+      if (!is) throw DataFormatError("PushBackReader format error");
+      is.putback(c);
+    }
+
+  };
+
+  /// \ingroup io_group
+  ///
+  /// \brief Reader for standard containers.
+  ///
+  /// Reader for insertable standard containers. The representation
+  /// of the container is the values enumerated between an open and a
+  /// close parse. 
+  ///
+  /// \author Balazs Dezso
+  template <
+    typename _Container, 
+    typename _ItemReader = DefaultReader<typename _Container::value_type> 
+  >
+  class InsertReader {
+  public:
+    typedef _Container Value;
+    typedef _ItemReader ItemReader;
+
+  private:
+
+    ItemReader item_reader;
+
+  public:
+
+    /// \brief Reads the values into the container from the given stream.
+    ///
+    /// Reads the values into the container from the given stream.
+    void read(std::istream& is, Value& value) const {
+      char c;
+      if (!(is >> c) || c != '(') 
+	throw DataFormatError("InsertReader format error");
+      while (is >> c && c != ')') {
+	is.putback(c);
+	typename ItemReader::Value item;
+	item_reader.read(is, item);
+	value.insert(item);
+      }
+      if (!is) throw DataFormatError("PushBackReader format error");
+      is.putback(c);
+    }
+
+  };
+
+  /// \ingroup io_group
+  /// \brief Reader for parsed string.
+  ///
+  /// Reader for parsed strings. You can give the open and close
+  /// parse characters.
+  ///
+  /// \author Balazs Dezso
+  class ParsedStringReader {
+  public:
+    typedef std::string Value;
+
+    /// \brief Constructor.
+    ///
+    /// Constructor for ParsedStringReader. You can give as parameter
+    /// the open and close parse characters.
+    ParsedStringReader(char _open = '(', char _close = ')')
+      : open(_open), close(_close) {}
+    
+    
+    /// \brief Reads the parsed string from the given stream.
+    ///
+    /// Reads the parsed string from the given stream.
+    void read(std::istream& is, Value& value) const {
+      char c;
+      if (!(is >> c) || c != open) {
+	throw DataFormatError("ParsedStringReader format error");
+      }
+      value += c;
+      int counter = 1;
+      while (counter > 0 && is >> c) {
+	if (c == close) {
+	  --counter;
+	} else if (c == open) {
+	  ++counter;
+	}
+	value += c;
+      }
+      if (!is) {
+	throw DataFormatError("ParsedStrinReader format error");
+      }
+    }
+
+  private:
+    char open, close;
+
+  };
+
+  /// \ingroup io_group
+  /// \brief Reader for read the whole line.
+  ///
+  /// Reader for read the whole line.
+  ///
+  /// \author Balazs Dezso
+  class LineReader {
+  public:
+    typedef std::string Value;
+
+    /// \brief Constructor.
+    ///
+    /// Constructor for the LineReader. If the given parameter is
+    /// true then the spaces before the first not space character are
+    /// skipped.
+    LineReader(bool _skipSpaces = true) : skipSpaces(_skipSpaces) {}
+    
+    /// \brief Reads the line from the given stream.
+    ///
+    /// Reads the line from the given stream.
+    void read(std::istream& is, Value& value) {
+      if (skipSpaces) is >> std::ws;
+      if (!getline(is, value)) {
+	throw DataFormatError("LineReader forma error");
+      }
+    }
+  private:
+    bool skipSpaces;
+  };
+
+  /// \ingroup io_group
+  /// 
+  /// \brief The default item reader template class.
+  ///
+  /// The default item reader template class. If some section reader
+  /// needs to read a value from a stream it will give the default way for it.
+  ///
+  /// \author Balazs Dezso
+  template <typename _Value>
+  class DefaultReader {
+  public:
+    /// The value type.
+    typedef _Value Value;
+    /// \brief Reads a value from the given stream.
+    ///
+    /// Reads a value from the given stream.
+    void read(std::istream& is, Value& value) const {
+      if (!(is >> value)) 
+	throw DataFormatError("DefaultReader format error");
+    }
+  };
+
+  template <typename Item>
+  class DefaultReader<std::vector<Item> > 
+    : public PushBackReader<std::vector<Item> > {};
+
+  template <typename Item>
+  class DefaultReader<std::deque<Item> > 
+    : public PushBackReader<std::deque<Item> > {};
+
+  template <typename Item>
+  class DefaultReader<std::list<Item> > 
+    : public PushBackReader<std::list<Item> > {};
+
+  template <typename Item>
+  class DefaultReader<std::set<Item> > 
+    : public InsertReader<std::set<Item> > {};
+
+  template <typename Item>
+  class DefaultReader<std::multiset<Item> > 
+    : public InsertReader<std::multiset<Item> > {};
+
+  /// \ingroup io_group
+  class DefaultSkipper {
+  public:
+    typedef std::string Value;
+    
+    void read(std::istream& is, Value& value) const {
+      char c;
+      if (!(is >> c)) return;
+      is.putback(c);
+      switch (c) {
+      case '\"':
+	QuotedStringReader().read(is, value);
+	break;
+      case '(':
+	ParsedStringReader().read(is, value);
+	break;
+      default:
+	DefaultReader<std::string>().read(is, value); 
+	break;
+      }
+    }
+  };
+  
+  /// \brief Standard ReaderTraits for the GraphReader class.
+  ///
+  /// Standard ReaderTraits for the GraphReader class.
+  /// It defines standard reading method for all type of value. 
+  /// \author Balazs Dezso
+  struct DefaultReaderTraits {
+
+    template <typename _Value>
+    struct Reader : DefaultReader<_Value> {};
+
+    typedef DefaultSkipper Skipper;
+
+  };
+
+}
+
+#endif
Index: src/lemon/graph_reader.h
===================================================================
--- src/lemon/graph_reader.h	(revision 1396)
+++ src/lemon/graph_reader.h	(revision 1408)
@@ -23,13 +23,7 @@
 
 #include <iostream>
-#include <sstream>
-
-#include <map>
-#include <vector>
-
-#include <memory>
 
 #include <lemon/error.h>
-
+#include <lemon/lemon_reader.h>
 
 namespace lemon {
@@ -38,155 +32,5 @@
   /// @{
 
-  /// \brief Standard ReaderTraits for the GraphReader class.
-  ///
-  /// Standard ReaderTraits for the GraphReader class.
-  /// It defines standard reading method for all type of value. 
-  /// \author Balazs Dezso
-  struct DefaultReaderTraits {
-
-    /// \brief Template class for reading an value.
-    ///
-    /// Template class for reading an value.
-    /// \author Balazs Dezso
-    template <typename _Value>
-    struct Reader {
-      /// The value type.
-      typedef _Value Value;
-      /// \brief Reads a value from the given stream.
-      ///
-      /// Reads a value from the given stream.
-      void read(std::istream& is, Value& value) {
-	if (!(is >> value)) 
-	  throw DataFormatError("Default reader format exception");
-      }
-    };
-
-    /// \brief Returns wheter this name is an ID map name.
-    ///
-    /// Returns wheter this name is an ID map name.
-    static bool idMapName(const std::string& name) {
-      return name == "id";
-    }
-
-    /// The reader class for the not needed maps.
-    typedef Reader<std::string> DefaultReader;
-
-  };
-
-  /// \brief Reader class for quoted strings.
-  ///
-  /// Reader class for quoted strings. It can process the escape
-  /// sequences in the string.
-  /// \author Balazs Dezso
-  class QuotedStringReader {
-  public:
-    typedef std::string Value;
-    
-    /// \brief Constructor for the reader.
-    ///
-    /// Constructor for the reader. If the given parameter is true
-    /// the reader processes the escape sequences.
-    QuotedStringReader(bool _escaped = true) : escaped(_escaped) {}
-    
-    /// \brief Reads a quoted string from the given stream.
-    ///
-    /// Reads a quoted string from the given stream.
-    void read(std::istream& is, std::string& value) {
-      char c;
-      value.clear();
-      is >> std::ws;
-      if (!is.get(c) || c != '\"') 
-	throw DataFormatError("Quoted string format error");
-      while (is.get(c) && c != '\"') {
-	if (escaped && c == '\\') {
-	  value += readEscape(is);
-	} else {
-	  value += c;
-	}
-      }
-      if (!is) throw DataFormatError("Quoted string format error");
-    }
-
-  private:
-    
-    static char readEscape(std::istream& is) {
-      char c;
-      switch (is.get(c), c) {
-      case '\\':
-	return '\\';
-      case '\"':
-	return '\"';
-      case '\'':
-	return '\'';
-      case '\?':
-	return '\?';
-      case 'a':
-	return '\a';
-      case 'b':
-	return '\b';
-      case 'f':
-	return '\f';
-      case 'n':
-	return '\n';
-      case 'r':
-	return '\r';
-      case 't':
-	return '\t';
-      case 'v':
-	return '\v';
-      case 'x':
-	{
-	  int code;
-	  if (!is.get(c) || !isHex(c)) 
-	    throw DataFormatError("Escape format error");
-	  else if (code = valueHex(c), !is.get(c) || !isHex(c)) is.putback(c);
-	  else code = code * 16 + valueHex(c);
-	  return code;
-	}
-      default:
-	{
-	  int code;
-	  if (!isOct(c)) 
-	    throw DataFormatError("Escape format error");
-	  else if (code = valueOct(c), !is.get(c) || !isOct(c)) 
-	    is.putback(c);
-	  else if (code = code * 8 + valueOct(c), !is.get(c) || !isOct(c)) 
-	    is.putback(c);
-	  else code = code * 8 + valueOct(c);
-	  return code;
-	}	      
-      } 
-    }
-
-    static bool isOct(char c) {
-      return '0' <= c && c <='7'; 
-    }
-    
-    static int valueOct(char c) {
-      return c - '0';
-    }
-
-   static bool isHex(char c) {
-      return ('0' <= c && c <= '9') || 
-	('a' <= c && c <= 'z') || 
-	('A' <= c && c <= 'Z'); 
-    }
-    
-    static int valueHex(char c) {
-      if ('0' <= c && c <= '9') return c - '0';
-      if ('a' <= c && c <= 'z') return c - 'a' + 10;
-      return c - 'A' + 10;
-    }
-
-    bool escaped;
-  };
-
-  class GUIReader {
-  public:
-    virtual void read(std::istream& is) = 0;
-  };
-
   /// \brief The graph reader class.
-  ///
   ///
   /// The given file format may contain several maps and labeled nodes or 
@@ -230,6 +74,6 @@
   /// \endcode
   ///
-  /// With \c readNode() and \c readEdge() functions you can read labeled Nodes 
-  /// and Edges.
+  /// With \c readNode() and \c readEdge() functions you can read 
+  /// labeled Nodes and Edges.
   ///
   /// \code
@@ -239,4 +83,8 @@
   /// reader.readEdge("observed", edge);
   /// \endcode
+  ///
+  /// With the \c readAttribute() functions you can read an attribute
+  /// in a variable. You can specify the reader for the attribute as
+  /// the nodemaps.
   ///
   /// After you give all read commands you must call the \c run() member
@@ -261,5 +109,5 @@
 
     typedef _ReaderTraits ReaderTraits;
-    typedef typename ReaderTraits::DefaultReader DefaultReader;
+    typedef typename ReaderTraits::Skipper DefaultSkipper;
 
     /// \brief Construct a new GraphReader.
@@ -268,7 +116,40 @@
     /// and it use the given reader as the default skipper.
     GraphReader(std::istream& _is, Graph& _graph, 
-		const DefaultReader& _reader = DefaultReader()) 
-      : gui_reader(0), is(_is), graph(_graph), 
-	nodeSkipper(_reader), edgeSkipper(_reader) {}
+		const DefaultSkipper& _skipper = DefaultSkipper()) 
+      : reader(new LemonReader(_is)), own_reader(true), 
+	graph(_graph), skipper(_skipper),
+	nodeset_reader(*reader, graph, std::string(), skipper),
+	edgeset_reader(*reader, graph, nodeset_reader, std::string(), skipper),
+	node_reader(*reader, nodeset_reader, std::string()),
+	edge_reader(*reader, edgeset_reader, std::string()),
+	attribute_reader(*reader, std::string()) {}
+
+    /// \brief Construct a new GraphReader.
+    ///
+    /// Construct a new GraphReader. It reads into the given graph
+    /// and it use the given reader as the default skipper.
+    GraphReader(const std::string& _filename, Graph& _graph, 
+		const DefaultSkipper& _skipper = DefaultSkipper()) 
+      : reader(new LemonReader(_filename)), own_reader(true), 
+	graph(_graph), skipper(_skipper),
+	nodeset_reader(*reader, graph, std::string(), skipper),
+	edgeset_reader(*reader, graph, nodeset_reader, std::string(), skipper),
+	node_reader(*reader, nodeset_reader, std::string()),
+	edge_reader(*reader, edgeset_reader, std::string()),
+	attribute_reader(*reader, std::string()) {}
+
+    /// \brief Construct a new GraphReader.
+    ///
+    /// Construct a new GraphReader. It reads into the given graph
+    /// and it use the given reader as the default skipper.
+    GraphReader(LemonReader& _reader, Graph& _graph, 
+		const DefaultSkipper& _skipper = DefaultSkipper()) 
+      : reader(_reader), own_reader(false), 
+	graph(_graph), skipper(_skipper),
+	nodeset_reader(*reader, graph, std::string(), skipper),
+	edgeset_reader(*reader, graph, nodeset_reader, std::string(), skipper),
+	node_reader(*reader, nodeset_reader, std::string()),
+	edge_reader(*reader, edgeset_reader, std::string()),
+	attribute_reader(*reader, std::string()) {}
 
     /// \brief Destruct the graph reader.
@@ -276,14 +157,6 @@
     /// Destruct the graph reader.
     ~GraphReader() {
-      for (typename NodeMapReaders::iterator it = node_map_readers.begin(); 
-	   it != node_map_readers.end(); ++it) {
-	delete it->second;
-      }
-
-      for (typename EdgeMapReaders::iterator it = edge_map_readers.begin(); 
-	   it != edge_map_readers.end(); ++it) {
-	delete it->second;
-      }
-
+      if (own_reader) 
+	delete reader;
     }
 
@@ -293,6 +166,6 @@
     template <typename Map>
     GraphReader& readNodeMap(std::string name, Map& map) {
-      return readNodeMap<typename ReaderTraits::template 
-	Reader<typename Map::Value>, Map>(name, map);
+      nodeset_reader.readMap(name, map);
+      return *this;
     }
 
@@ -303,11 +176,5 @@
     GraphReader& readNodeMap(std::string name, Map& map, 
 			     const Reader& reader = Reader()) {
-      if (node_map_readers.find(name) != node_map_readers.end()) {
-	ErrorMessage msg;
-	msg << "Multiple read rule for node map: " << name;
-	throw IOParameterError(msg.message());
-      }
-      node_map_readers.insert(
-        make_pair(name, new MapReader<Node, Map, Reader>(map, reader)));
+      nodeset_reader.readMap(name, map, reader);
       return *this;
     }
@@ -319,11 +186,5 @@
     GraphReader& skipNodeMap(std::string name, 
 			     const Reader& reader = Reader()) {
-      if (node_map_readers.find(name) != node_map_readers.end()) {
-	ErrorMessage msg;
-	msg << "Multiple read rule for node map: " << name;
-	throw IOParameterError(msg.message());
-      }
-      node_map_readers.insert(
-        make_pair(name, new SkipReader<Node, Reader>(reader)));
+      nodeset_reader.skipMap(name, reader);
       return *this;
     }
@@ -334,6 +195,6 @@
     template <typename Map>
     GraphReader& readEdgeMap(std::string name, Map& map) { 
-      return readEdgeMap<typename ReaderTraits::template
-	Reader<typename Map::Value>, Map>(name, map);
+      edgeset_reader.readMap(name, map);
+      return *this;
     }
 
@@ -345,11 +206,5 @@
     GraphReader& readEdgeMap(std::string name, Map& map,
 			     const Reader& reader = Reader()) {
-      if (edge_map_readers.find(name) != edge_map_readers.end()) {
-	ErrorMessage msg;
-	msg << "Multiple read rule for edge map: " << name;
-	throw IOParameterError(msg.message());
-      }
-      edge_map_readers.insert(
-        make_pair(name, new MapReader<Edge, Map, Reader>(map, reader)));
+      edgeset_reader.readMap(name, map, reader);
       return *this;
     }
@@ -361,11 +216,6 @@
     GraphReader& skipEdgeMap(std::string name,
 			     const Reader& reader = Reader()) {
-      if (edge_map_readers.find(name) != edge_map_readers.end()) {
-	ErrorMessage msg;
-	msg << "Multiple read rule for edge map: " << name;
-	throw IOParameterError(msg.message());
-      }
-      edge_map_readers.insert(
-        make_pair(name, new SkipReader<Edge, Reader>(reader)));
+
+      edgeset_reader.skipMap(name, reader);
       return *this;
     }
@@ -375,10 +225,5 @@
     /// Add a new labeled node reader for the reader.
     GraphReader& readNode(std::string name, Node& node) {
-      if (node_readers.find(name) != node_readers.end()) {
-	ErrorMessage msg;
-	msg << "Multiple read rule for node: " << name;
-	throw IOParameterError(msg.message());
-      }
-      node_readers.insert(make_pair(name, &node));
+      node_reader.readNode(name, node);
       return *this;
     }
@@ -388,11 +233,34 @@
     /// Add a new labeled edge reader for the reader.
     GraphReader& readEdge(std::string name, Edge& edge) {
-      if (edge_readers.find(name) != edge_readers.end()) {
-	ErrorMessage msg;
-	msg << "Multiple read rule for edge: " << name;
-	throw IOParameterError(msg.message());
-      }
-      edge_readers.insert(make_pair(name, &edge));
-      return *this;
+      edge_reader.readEdge(name, edge);
+    }
+
+    /// \brief Add a new attribute reader command.
+    ///
+    ///  Add a new attribute reader command.
+    template <typename Value>
+    GraphReader& readAttribute(std::string name, Value& value) {
+      attribute_reader.readAttribute(name, value);
+      return *this;
+    }
+    
+    /// \brief Add a new attribute reader command.
+    ///
+    ///  Add a new attribute reader command.
+    template <typename Reader, typename Value>
+    GraphReader& readAttribute(std::string name, Value& value, 
+			       const Reader& reader) {
+      attribute_reader.readAttribute<Reader>(name, value, reader);
+      return *this;
+    }
+
+    /// \brief Conversion operator to LemonReader.
+    ///
+    /// Conversion operator to LemonReader. It make possible
+    /// to access the encapsulated \e LemonReader, this way
+    /// you can attach to this reader new instances of 
+    /// \e LemonReader::SectionReader.
+    operator LemonReader&() {
+      return *reader;
     }
 
@@ -401,370 +269,23 @@
     /// Executes the reader commands.
     void run() {
-      int line_num = 0;
-      std::auto_ptr<InverterBase<Node> > nodeInverter;
-      std::auto_ptr<InverterBase<Edge> > edgeInverter;
-      try {
-	std::string line = readNotEmptyLine(is, line_num);
-	if (line.find("@nodeset") == 0) {
-	  line = readNodeSet(line_num, nodeInverter);
-	} 
-	if (line.find("@edgeset") == 0) {
-	  line = readEdgeSet(line_num, edgeInverter, nodeInverter);
-	}
-	if (line.find("@nodes") == 0) {
-	  line = readNodes(line_num, nodeInverter);
-	}
-	if (line.find("@edges") == 0) {
-	  line = readEdges(line_num, edgeInverter);
-	}
-	if (line.find("@gui") == 0) {
-	  line = readGUI(line_num);
-	}
-	if (line.find("@end") != 0) {
-	  throw DataFormatError("Invalid control sequence error");
-	}
-      } catch (DataFormatError e) {
-	e.line(line_num);
-	throw e;
-      }
-    }
-
-    GraphReader& readGUI(GUIReader& reader) {
-      gui_reader = &reader;
-      return *this;
+      reader->run();
     }
 
   private:
 
-    template <typename Item> class InverterBase;
-
-    std::string readNodeSet(int& line_num, 
-			    std::auto_ptr<InverterBase<Node> >& nodeInverter) {
-      std::vector<ReaderBase<Node>* > index;
-      {
-	std::string line = readNotEmptyLine(is, line_num);    
-	std::string id;
-	std::istringstream ls(line);	
-	while (ls >> id) {
-	  typename NodeMapReaders::iterator it = node_map_readers.find(id);
-	  if (it != node_map_readers.end()) {
-	    index.push_back(it->second);
-	    node_map_readers.erase(it);
-	  } else {
-	    index.push_back(&nodeSkipper);
-	  }
-	  if (ReaderTraits::idMapName(id) && nodeInverter.get() == 0) {
-	    nodeInverter.reset(index.back()->getInverter());
-	    index.back() = nodeInverter.get();
-	  }
-	}
-      }
-
-//       if (index.size() == 0) {
-// 	throw DataFormatError("Cannot find node id map");
-//       }
-
-//       nodeInverter = 
-// 	std::auto_ptr<InverterBase<Node> >(index[0]->getInverter());
-      std::string line;
-      while (line = readNotEmptyLine(is, line_num), line[0] != '@') {
-	Node node = graph.addNode();
-	std::istringstream ls(line);
-	for (int i = 0; i < (int)index.size(); ++i) {
-	  index[i]->read(ls, node);
-	}
-      }
-      return line;
-    }
-
-    std::string readEdgeSet(int& line_num, 
-			    std::auto_ptr<InverterBase<Edge> >& edgeInverter, 
-			    std::auto_ptr<InverterBase<Node> >& nodeInverter) {
-      std::vector<ReaderBase<Edge>*> index;
-      {
-	std::string line = readNotEmptyLine(is, line_num);    
-	std::string id;
-	std::istringstream ls(line);	
-	while (ls >> id) {
-	  typename EdgeMapReaders::iterator it = edge_map_readers.find(id);
-	  if (it != edge_map_readers.end()) {
-	    index.push_back(it->second);
-	    edge_map_readers.erase(it);
-	  } else {
-	    index.push_back(&edgeSkipper);
-	  }
-	  if (ReaderTraits::idMapName(id) && edgeInverter.get() == 0) {
-	    edgeInverter.reset(index.back()->getInverter());
-	    index.back() = edgeInverter.get();
-	  }
-	}
-      }
-      
-      if (nodeInverter.get() == 0) {
- 	throw DataFormatError("Cannot find node id map");
-      }
-//       if (index.size() == 0) {
-// 	throw DataFormatError("Cannot find edge id map");
-//       }
-
-//       edgeInverter = 
-// 	std::auto_ptr<InverterBase<Edge> >(index[0]->getInverter());
-      std::string line;
-      while (line = readNotEmptyLine(is, line_num), line[0] != '@') {	
-	std::istringstream ls(line);
-	Node source = nodeInverter->read(ls);
-	Node target = nodeInverter->read(ls);
-	Edge edge = graph.addEdge(source, target);
-	for (int i = 0; i < (int)index.size(); ++i) {
-	  index[i]->read(ls, edge);
-	}
-      }      
-      return line;
-    }
-
-    std::string readNodes(int& line_num, 
-			  std::auto_ptr<InverterBase<Node> >& nodeInverter) {
-      std::string line;
-      if (nodeInverter.get() == 0) {
- 	throw DataFormatError("Cannot find node id map");
-      }
-      while (line = readNotEmptyLine(is, line_num), line[0] != '@') {
-	std::istringstream ls(line);
-	std::string name;
-	ls >> name;
-	typename NodeReaders::iterator it = node_readers.find(name);
-	if (it != node_readers.end()) {
-	  *(it -> second) = nodeInverter->read(ls);
-	} 
-      }        
-      return line;
-    }
-
-    std::string readEdges(int& line_num, 
-			  std::auto_ptr<InverterBase<Edge> >& edgeInverter) {
-      std::string line;
-      if (edgeInverter.get() == 0) {
- 	throw DataFormatError("Cannot find edge id map");
-      }
-      while (line = readNotEmptyLine(is, line_num), line[0] != '@') {
-	std::istringstream ls(line);
-	std::string name;
-	ls >> name;
-	typename EdgeReaders::iterator it = edge_readers.find(name);
-	if (it != edge_readers.end()) {
-	  *(it -> second) = edgeInverter->read(ls);
-	} 
-      }        
-      return line;    
-    }
-
-    std::string readGUI(int& line_num) {
-      std::stringstream section;
-      std::string line;
-      while (line = readNotEmptyLine(is, line_num), line[0] != '@') {
-	section << line << std::endl;
-      }
-      if (gui_reader != 0) {
-	gui_reader->read(section);
-      }
-      return line;
-    }
-
-    std::string readNotEmptyLine(std::istream& is, int& line_num) {
-      std::string line;
-      while (++line_num, getline(is, line)) {	
-	int vi = line.find('#');
-	if (vi != (int)::std::string::npos) {
-	  line = line.substr(0, vi);
-	}
-	vi = line.find_first_not_of(" \t");
-	if (vi != (int)std::string::npos) { 
-	  return line.substr(vi);
-	}
-      }
-      throw DataFormatError("End of stream error");
-    }
+    LemonReader* reader;
+    bool own_reader;
+
+    Graph& graph;
+
+    DefaultSkipper skipper;
+
+    NodeSetReader<Graph, ReaderTraits> nodeset_reader;
+    EdgeSetReader<Graph, ReaderTraits> edgeset_reader;
+
+    NodeReader<Graph> node_reader;
+    EdgeReader<Graph> edge_reader;
     
-    template <typename _Item>
-    class ReaderBase;
-    
-    template <typename _Item>
-    class InverterBase : public ReaderBase<_Item> {
-    public:
-      typedef _Item Item;
-      virtual void read(std::istream&, const Item&) = 0;
-      virtual Item read(std::istream&) = 0;
-
-      virtual InverterBase<_Item>* getInverter() {
-	return this;
-      }
-    };
-
-    template <typename _Item, typename _Map, typename _Reader>
-    class MapReaderInverter : public InverterBase<_Item> {
-    public:
-      typedef _Item Item;
-      typedef _Reader Reader;
-      typedef typename Reader::Value Value;
-      typedef _Map Map;
-      typedef std::map<Value, Item> Inverse;
-
-      Map& map;
-      Reader reader;
-      Inverse inverse;
-
-      MapReaderInverter(Map& _map, const Reader& _reader) 
-	: map(_map), reader(_reader) {}
-
-      virtual ~MapReaderInverter() {}
-
-      virtual void read(std::istream& is, const Item& item) {
-	Value value;
-	reader.read(is, value);
-	map.set(item, value);
-	typename Inverse::iterator it = inverse.find(value);
-	if (it == inverse.end()) {
-	  inverse.insert(std::make_pair(value, item));
-	} else {
-	  throw DataFormatError("Multiple ID occurence");
-	}
-      }
-
-      virtual Item read(std::istream& is) {
-	Value value;
-	reader.read(is, value);	
-	typename Inverse::const_iterator it = inverse.find(value);
-	if (it != inverse.end()) {
-	  return it->second;
-	} else {
-	  throw DataFormatError("Invalid ID error");
-	}
-      }      
-    };
-
-    template <typename _Item, typename _Reader>
-    class SkipReaderInverter : public InverterBase<_Item> {
-    public:
-      typedef _Item Item;
-      typedef _Reader Reader;
-      typedef typename Reader::Value Value;
-      typedef std::map<Value, Item> Inverse;
-
-      Reader reader;
-
-      SkipReaderInverter(const Reader& _reader) 
-	: reader(_reader) {}
-
-      virtual ~SkipReaderInverter() {}
-
-      virtual void read(std::istream& is, const Item& item) {
-	Value value;
-	reader.read(is, value);
-	typename Inverse::iterator it = inverse.find(value);
-	if (it == inverse.end()) {
-	  inverse.insert(std::make_pair(value, item));
-	} else {
-	  throw DataFormatError("Multiple ID occurence error");
-	}
-      }
-
-      virtual Item read(std::istream& is) {
-	Value value;
-	reader.read(is, value);	
-	typename Inverse::const_iterator it = inverse.find(value);
-	if (it != inverse.end()) {
-	  return it->second;
-	} else {
-	  throw DataFormatError("Invalid ID error");
-	}
-      }      
-    private:
-      Inverse inverse;
-    };
-
-    // Readers
-
-    template <typename _Item>    
-    class ReaderBase {
-    public:
-      typedef _Item Item;
-
-      //      virtual ~ReaderBase() {}
-
-      virtual void read(std::istream& is, const Item& item) = 0;
-      virtual InverterBase<_Item>* getInverter() = 0;
-    };
-
-    template <typename _Item, typename _Map, typename _Reader>
-    class MapReader : public ReaderBase<_Item> {
-    public:
-      typedef _Map Map;
-      typedef _Reader Reader;
-      typedef typename Reader::Value Value;
-      typedef _Item Item;
-      
-      Map& map;
-      Reader reader;
-
-      MapReader(Map& _map, const Reader& _reader) 
-	: map(_map), reader(_reader) {}
-
-      virtual ~MapReader() {}
-
-      virtual void read(std::istream& is, const Item& item) {
-	Value value;
-	reader.read(is, value);
-	map.set(item, value);
-      }
-
-      virtual InverterBase<_Item>* getInverter() {
-	return new MapReaderInverter<Item, Map, Reader>(map, reader);
-      }
-    };
-
-
-    template <typename _Item, typename _Reader>
-    class SkipReader : public ReaderBase<_Item> {
-    public:
-      typedef _Reader Reader;
-      typedef typename Reader::Value Value;
-      typedef _Item Item;
-
-      Reader reader;
-      SkipReader(const Reader& _reader) : reader(_reader) {}
-
-      virtual ~SkipReader() {}
-
-      virtual void read(std::istream& is, const Item&) {
-	Value value;
-	reader.read(is, value);
-      }      
-
-      virtual InverterBase<Item>* getInverter() {
-	return new SkipReaderInverter<Item, Reader>(reader);
-      }
-    };
-
-
-    typedef std::map<std::string, ReaderBase<Node>*> NodeMapReaders;
-    NodeMapReaders node_map_readers;
-
-    typedef std::map<std::string, ReaderBase<Edge>*> EdgeMapReaders;
-    EdgeMapReaders edge_map_readers;
-
-    typedef std::map<std::string, Node*> NodeReaders;
-    NodeReaders node_readers;
-
-    typedef std::map<std::string, Edge*> EdgeReaders;
-    EdgeReaders edge_readers;
-
-    GUIReader* gui_reader;
-
-    std::istream& is;
-    Graph& graph;
-
-    SkipReader<Node, DefaultReader> nodeSkipper;
-    SkipReader<Edge, DefaultReader> edgeSkipper;
-
+    AttributeReader<ReaderTraits> attribute_reader;
   };
 
Index: src/lemon/lemon_reader.h
===================================================================
--- src/lemon/lemon_reader.h	(revision 1408)
+++ src/lemon/lemon_reader.h	(revision 1408)
@@ -0,0 +1,977 @@
+/* -*- C++ -*-
+ * src/lemon/lemon_reader.h - Part of LEMON, a generic C++ optimization library
+ *
+ * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
+ * (Egervary Research Group on Combinatorial Optimization, EGRES).
+ *
+ * Permission to use, modify and distribute this software is granted
+ * provided that this copyright notice appears in all copies. For
+ * precise terms see the accompanying LICENSE file.
+ *
+ * This software is provided "AS IS" with no warranty of any kind,
+ * express or implied, and with no claim as to its suitability for any
+ * purpose.
+ *
+ */
+
+///\ingroup io_group
+///\file
+///\brief Lemon Format reader.
+
+#ifndef LEMON_LEMON_READER_H
+#define LEMON_LEMON_READER_H
+
+#include <iostream>
+#include <fstream>
+#include <string>
+#include <vector>
+#include <algorithm>
+#include <map>
+#include <memory>
+
+#include <lemon/error.h>
+#include "item_reader.h"
+
+
+namespace lemon {
+
+  /// \addtogroup io_group
+  /// @{
+
+  /// \brief Lemon Format reader class.
+  /// 
+  class LemonReader {
+  private:
+    
+    class FilterStreamBuf : public std::streambuf {
+    public:
+
+      typedef std::streambuf Parent;
+      typedef Parent::char_type char_type;
+      FilterStreamBuf(std::istream& is, int& num) 
+	: _is(is), _base(0), _eptr(0), 
+	  _num(num), skip_state(after_endl) {}
+
+    protected:
+
+      enum skip_state_type {
+	no_skip,
+	after_comment,
+	after_endl,
+	empty_line
+      };
+
+      char_type small_buf[1];
+
+
+      std::istream& _is;
+
+      char_type* _base;
+      char_type* _eptr;
+
+      int& _num;
+
+      skip_state_type skip_state;
+
+
+      char_type* base() { return _base; }
+
+      char_type* eptr() { return _eptr; }
+
+      int blen() { return _eptr - _base; }
+
+      void setb(char_type* buf, int len) {
+	_base = buf;
+	_eptr = buf + len;
+      }
+  
+      virtual std::streambuf* setbuf(char *buf, int len) {
+	if (base()) return 0;
+	if (buf != 0 && len >= (int)sizeof(small_buf)) {
+	  setb(buf, len);
+	} else {
+	  setb(small_buf, sizeof(small_buf));
+	}
+	setg(0, 0, 0);
+	return this;
+      }
+
+      bool put_char(char c) {
+	switch (skip_state) {
+	case no_skip:
+	  switch (c) {
+	  case '\n': 
+	    skip_state = after_endl;
+	    return true;
+	  case '#':
+	    skip_state = after_comment;
+	    return false;
+	  default:
+	    return true;
+	  }
+	case after_comment:
+	  switch (c) {
+	  case '\n': 
+	    skip_state = after_endl;
+	    return true;
+	  default:
+	    return false;
+	  }        
+	case after_endl:
+	  switch (c) {
+	  case '@':
+	    return false;
+	  case '\n': 
+	    return false;
+	  case '#':
+	    skip_state = empty_line;
+	    return false;
+	  default:
+	    if (!isspace(c)) {
+	      skip_state = no_skip;
+	      return true;
+	    } else {
+	      return false;
+	    }
+	  }
+	  break;
+	case empty_line:
+	  switch (c) {
+	  case '\n': 
+	    skip_state = after_endl;
+	    return false;
+	  default:
+	    return false;
+	  }
+	}
+	return false;
+      }
+
+      virtual int underflow() {
+	char c;
+	if (_is.read(&c, 1)) {
+	  _is.putback(c);
+	  if (c == '@') {
+	    return EOF;
+	  }
+	} else {
+	  return EOF;
+	}
+	char_type *ptr;
+	for (ptr = base(); ptr != eptr(); ++ptr) {
+	  if (_is.read(&c, 1)) {
+	    if (c == '\n') ++_num;
+	    if (put_char(c)) {
+	      *ptr = c;
+	    } else {
+	      if (skip_state == after_endl && c == '@') {
+		_is.putback('@');
+		break;
+	      }
+	      --ptr;
+	    }
+	  } else {
+	    break;
+	  }
+	}
+	setg(base(), base(), ptr);
+	return *base();
+      }
+
+      virtual int sync() {
+	return EOF;
+      }
+    };
+
+  public:
+
+    class SectionReader {
+    public:
+      /// \e
+      virtual bool header(const std::string& line) = 0;
+      /// \e
+      virtual void read(std::istream& is) = 0;
+    };
+
+    /// \e
+    LemonReader(std::istream& _is) 
+      : is(&_is), own_is(false) {}
+
+    LemonReader(const std::string& filename) 
+      : is(0), own_is(true) {
+      is = new std::ifstream(filename.c_str());
+    }
+
+
+    ~LemonReader() {
+      if (own_is) {
+	delete is;
+      }
+    }
+
+  private:
+    LemonReader(const LemonReader&);
+    void operator=(const LemonReader&);
+
+  public:
+    
+    /// \e
+    void attach(SectionReader& reader) {
+      readers.push_back(&reader);
+    }
+
+    /// \e
+    void detach(SectionReader& reader) {
+      std::vector<SectionReader*>::iterator it = 
+	std::find(readers.begin(), readers.end(), &reader);
+      if (it != readers.end()) {
+	readers.erase(it);
+      }
+    }
+
+    /// \e
+    void run() {
+      int line_num = 0;
+      std::string line;
+      try {
+	while ((++line_num, getline(*is, line)) && line.find("@end") != 0) {
+	  SectionReaders::iterator it;
+	  for (it = readers.begin(); it != readers.end(); ++it) {
+	    if ((*it)->header(line)) {
+	      char buf[2048];
+	      FilterStreamBuf buffer(*is, line_num);
+	      buffer.pubsetbuf(buf, sizeof(buf));
+	      std::istream is(&buffer);
+	      (*it)->read(is);
+	      break;
+	    }
+	  }
+	}
+      } catch (DataFormatError& error) {
+	error.line(line_num);
+	throw error;
+      }	
+    }
+
+
+  private:
+
+    std::istream* is;
+    bool own_is;
+
+    typedef std::vector<SectionReader*> SectionReaders;
+    SectionReaders readers;
+
+  };
+
+
+  /// \e
+  class CommonSectionReaderBase : public LemonReader::SectionReader {
+  protected:
+    template <typename _Item>
+    class ReaderBase;
+    
+    template <typename _Item>
+    class InverterBase : public ReaderBase<_Item> {
+    public:
+      typedef _Item Item;
+      virtual void read(std::istream&, const Item&) = 0;
+      virtual Item read(std::istream&) const = 0;
+
+      virtual InverterBase<_Item>* getInverter() {
+	return this;
+      }
+
+
+    };
+
+    template <typename _Item, typename _Map, typename _Reader>
+    class MapReaderInverter : public InverterBase<_Item> {
+    public:
+      typedef _Item Item;
+      typedef _Reader Reader;
+      typedef typename Reader::Value Value;
+      typedef _Map Map;
+      typedef std::map<Value, Item> Inverse;
+
+      Map& map;
+      Reader reader;
+      Inverse inverse;
+
+      MapReaderInverter(Map& _map, const Reader& _reader) 
+	: map(_map), reader(_reader) {}
+
+      virtual ~MapReaderInverter() {}
+
+      virtual void read(std::istream& is, const Item& item) {
+	Value value;
+	reader.read(is, value);
+	map.set(item, value);
+	typename Inverse::iterator it = inverse.find(value);
+	if (it == inverse.end()) {
+	  inverse.insert(std::make_pair(value, item));
+	} else {
+	  throw DataFormatError("Multiple ID occurence");
+	}
+      }
+
+      virtual Item read(std::istream& is) const {
+	Value value;
+	reader.read(is, value);	
+	typename Inverse::const_iterator it = inverse.find(value);
+	if (it != inverse.end()) {
+	  return it->second;
+	} else {
+	  throw DataFormatError("Invalid ID error");
+	}
+      }      
+
+    };
+
+    template <typename _Item, typename _Reader>
+    class SkipReaderInverter : public InverterBase<_Item> {
+    public:
+      typedef _Item Item;
+      typedef _Reader Reader;
+      typedef typename Reader::Value Value;
+      typedef std::map<Value, Item> Inverse;
+
+      Reader reader;
+
+      SkipReaderInverter(const Reader& _reader) 
+	: reader(_reader) {}
+
+      virtual ~SkipReaderInverter() {}
+
+      virtual void read(std::istream& is, const Item& item) {
+	Value value;
+	reader.read(is, value);
+	typename Inverse::iterator it = inverse.find(value);
+	if (it == inverse.end()) {
+	  inverse.insert(std::make_pair(value, item));
+	} else {
+	  throw DataFormatError("Multiple ID occurence error");
+	}
+      }
+
+      virtual Item read(std::istream& is) const {
+	Value value;
+	reader.read(is, value);	
+	typename Inverse::const_iterator it = inverse.find(value);
+	if (it != inverse.end()) {
+	  return it->second;
+	} else {
+	  throw DataFormatError("Invalid ID error");
+	}
+      }
+
+    private:
+      Inverse inverse;
+    };
+
+    // Readers
+
+    template <typename _Item>    
+    class ReaderBase {
+    public:
+      typedef _Item Item;
+
+      virtual ~ReaderBase() {}
+
+      virtual void read(std::istream& is, const Item& item) = 0;
+      virtual InverterBase<_Item>* getInverter() = 0;
+    };
+
+    template <typename _Item, typename _Map, typename _Reader>
+    class MapReader : public ReaderBase<_Item> {
+    public:
+      typedef _Map Map;
+      typedef _Reader Reader;
+      typedef typename Reader::Value Value;
+      typedef _Item Item;
+      
+      Map& map;
+      Reader reader;
+
+      MapReader(Map& _map, const Reader& _reader) 
+	: map(_map), reader(_reader) {}
+
+      virtual ~MapReader() {}
+
+      virtual void read(std::istream& is, const Item& item) {
+	Value value;
+	reader.read(is, value);
+	map.set(item, value);
+      }
+
+      virtual InverterBase<_Item>* getInverter() {
+	return new MapReaderInverter<Item, Map, Reader>(map, reader);
+      }
+    };
+
+
+    template <typename _Item, typename _Reader>
+    class SkipReader : public ReaderBase<_Item> {
+    public:
+      typedef _Reader Reader;
+      typedef typename Reader::Value Value;
+      typedef _Item Item;
+
+      Reader reader;
+      SkipReader(const Reader& _reader) : reader(_reader) {}
+
+      virtual ~SkipReader() {}
+
+      virtual void read(std::istream& is, const Item&) {
+	Value value;
+	reader.read(is, value);
+      }      
+
+      virtual InverterBase<Item>* getInverter() {
+	return new SkipReaderInverter<Item, Reader>(reader);
+      }
+    };
+
+    template <typename _Item>
+    class ResolverReaderBase {
+    public:
+      typedef _Item Item;
+      virtual Item resolve(std::istream& is) const = 0;
+    };
+
+    template <typename _Item, typename _Resolver>
+    class ResolverReader : public ResolverReaderBase<_Item> {
+    public:
+      typedef _Item Item;
+      typedef _Resolver Resolver;
+
+      const Resolver& resolver;
+
+      ResolverReader(const Resolver& _resolver) 
+	: resolver(_resolver) {}
+
+      virtual Item resolve(std::istream& is) const {
+	return resolver.resolve(is);
+      }
+    };
+
+    class ValueReaderBase {
+    public:
+      virtual void read(std::istream&) {};
+    };
+
+    template <typename _Value, typename _Reader>
+    class ValueReader : public ValueReaderBase {
+    public:
+      typedef _Value Value;
+      typedef _Reader Reader;
+
+      ValueReader(Value& _value, const Reader& _reader)
+ 	: value(_value), reader(_reader) {}
+
+      virtual void read(std::istream& is) {
+	reader.read(is, value);
+      }
+    private:
+      Value& value;
+      Reader reader;
+    };
+    
+  };
+
+
+  template <typename _Graph, typename _Traits = DefaultReaderTraits>
+  class NodeSetReader : public CommonSectionReaderBase {
+    typedef CommonSectionReaderBase Parent;
+  public:
+
+    typedef _Graph Graph;
+    typedef _Traits Traits;
+    typedef typename Graph::Node Item;
+    typedef typename Traits::Skipper DefaultSkipper;
+
+    NodeSetReader(LemonReader& _reader, Graph& _graph, 
+		  const std::string& _id = std::string(),
+		  const DefaultSkipper& _defreader = DefaultSkipper()) 
+      : graph(_graph), id(_id), skipper(_defreader) {
+      _reader.attach(*this);
+    } 
+
+    virtual ~NodeSetReader() {
+      for (typename MapReaders::iterator it = readers.begin(); 
+	   it != readers.end(); ++it) {
+	delete it->second;
+      }
+    }
+
+  private:
+    NodeSetReader(const NodeSetReader&);
+    void operator=(const NodeSetReader&);
+  
+  public:
+
+    /// \brief Add a new node map reader command for the reader.
+    ///
+    /// Add a new node map reader command for the reader.
+    template <typename Map>
+    NodeSetReader& readMap(std::string name, Map& map) {
+      return readMap<typename Traits::
+	template Reader<typename Map::Value>, Map>(name, map);
+    }
+
+    /// \brief Add a new node map reader command for the reader.
+    ///
+    /// Add a new node map reader command for the reader.
+    template <typename Reader, typename Map>
+    NodeSetReader& readMap(std::string name, Map& map, 
+			     const Reader& reader = Reader()) {
+      if (readers.find(name) != readers.end()) {
+	ErrorMessage msg;
+	msg << "Multiple read rule for node map: " << name;
+	throw IOParameterError(msg.message());
+      }
+      readers.insert(
+	make_pair(name, new MapReader<Item, Map, Reader>(map, reader)));
+      return *this;
+    }
+
+    /// \brief Add a new node map skipper command for the reader.
+    ///
+    /// Add a new node map skipper command for the reader.
+    template <typename Reader>
+    NodeSetReader& skipMap(std::string name, 
+			   const Reader& reader = Reader()) {
+      if (readers.find(name) != readers.end()) {
+	ErrorMessage msg;
+	msg << "Multiple read rule for node map: " << name;
+	throw IOParameterError(msg.message());
+      }
+      readers.insert(make_pair(name, new SkipReader<Item, Reader>(reader)));
+      return *this;
+    }
+
+    /// \e
+    virtual bool header(const std::string& line) {
+      std::istringstream ls(line);
+      std::string command;
+      std::string name;
+      ls >> command >> name;
+      return command == "@nodeset" && name == id;
+    }
+
+    /// \e
+    virtual void read(std::istream& is) {
+      std::vector<ReaderBase<Item>* > index;
+      std::string line;
+
+      getline(is, line);
+      std::istringstream ls(line);	
+      while (ls >> id) {
+	typename MapReaders::iterator it = readers.find(id);
+	if (it != readers.end()) {
+	  index.push_back(it->second);
+	} else {
+	  index.push_back(&skipper);
+	}
+	if (id == "id" && inverter.get() == 0) {
+	  inverter.reset(index.back()->getInverter());
+	  index.back() = inverter.get();
+	}
+      }
+      while (getline(is, line)) {	
+	typename Graph::Node node = graph.addNode();
+	std::istringstream ls(line);
+	for (int i = 0; i < (int)index.size(); ++i) {
+	  index[i]->read(ls, node);
+	}
+      }
+    }
+
+    bool isResolver() const {
+      return inverter.get() != 0;
+    }
+
+    typename Graph::Node resolve(std::istream& is) const {
+      return inverter->read(is);
+    } 
+
+  private:
+
+    typedef std::map<std::string, ReaderBase<Item>*> MapReaders;
+    MapReaders readers;
+   
+    Graph& graph;   
+    std::string id;
+    SkipReader<Item, DefaultSkipper> skipper;
+
+    std::auto_ptr<InverterBase<Item> > inverter;
+  };
+
+
+ 
+  /// \e
+  template <typename _Graph, typename _Traits = DefaultReaderTraits>
+  class EdgeSetReader : public CommonSectionReaderBase {
+    typedef CommonSectionReaderBase Parent;
+  public:
+
+    typedef _Graph Graph;
+    typedef _Traits Traits;
+    typedef typename Graph::Edge Item;
+    typedef typename Traits::Skipper DefaultSkipper;
+
+    template <typename Resolver>
+    EdgeSetReader(LemonReader& _reader, Graph& _graph, 
+		  const Resolver& _nodeResolver, 
+		  const std::string& _id = std::string(),
+		  const DefaultSkipper& _defreader = DefaultSkipper()) 
+      : graph(_graph), id(_id), skipper(_defreader),
+      nodeResolver(new ResolverReader<typename Graph::Node, Resolver>
+		   (_nodeResolver)) {
+      _reader.attach(*this);
+    } 
+
+    virtual ~EdgeSetReader() {
+      for (typename MapReaders::iterator it = readers.begin(); 
+	   it != readers.end(); ++it) {
+	delete it->second;
+      }
+    }
+
+  private:
+    EdgeSetReader(const EdgeSetReader&);
+    void operator=(const EdgeSetReader&);
+
+  public:
+
+    /// \brief Add a new node map reader command for the reader.
+    ///
+    /// Add a new node map reader command for the reader.
+    template <typename Map>
+    EdgeSetReader& readMap(std::string name, Map& map) {
+      return readMap<typename Traits::
+	template Reader<typename Map::Value>, Map>(name, map);
+    }
+
+    /// \brief Add a new node map reader command for the reader.
+    ///
+    /// Add a new node map reader command for the reader.
+    template <typename Reader, typename Map>
+    EdgeSetReader& readMap(std::string name, Map& map, 
+			     const Reader& reader = Reader()) {
+      if (readers.find(name) != readers.end()) {
+	ErrorMessage msg;
+	msg << "Multiple read rule for edge map: " << name;
+	throw IOParameterError(msg.message());
+      }
+      readers.insert(
+	make_pair(name, new MapReader<Item, Map, Reader>(map, reader)));
+      return *this;
+    }
+
+    /// \brief Add a new node map skipper command for the reader.
+    ///
+    /// Add a new node map skipper command for the reader.
+    template <typename Reader>
+    EdgeSetReader& skipMap(std::string name, 
+			   const Reader& reader = Reader()) {
+      if (readers.find(name) != readers.end()) {
+	ErrorMessage msg;
+	msg << "Multiple read rule for node map: " << name;
+	throw IOParameterError(msg.message());
+      }
+      readers.insert(make_pair(name, new SkipReader<Item, Reader>(reader)));
+      return *this;
+    }
+
+    /// \e
+    virtual bool header(const std::string& line) {
+      std::istringstream ls(line);
+      std::string command;
+      std::string name;
+      ls >> command >> name;
+      return command == "@edgeset" && name == id;
+    }
+
+    /// \e
+    virtual void read(std::istream& is) {
+      std::vector<ReaderBase<Item>* > index;
+      std::string line;
+
+      getline(is, line);
+      std::istringstream ls(line);	
+      while (ls >> id) {
+	typename MapReaders::iterator it = readers.find(id);
+	if (it != readers.end()) {
+	  index.push_back(it->second);
+	} else {
+	  index.push_back(&skipper);
+	}
+	if (id == "id" && inverter.get() == 0) {
+	  inverter.reset(index.back()->getInverter());
+	  index.back() = inverter.get();
+	}
+      }
+      while (getline(is, line)) {	
+	std::istringstream ls(line);
+	typename Graph::Node from = nodeResolver->resolve(ls);
+	typename Graph::Node to = nodeResolver->resolve(ls);
+	typename Graph::Edge edge = graph.addEdge(from, to);
+	for (int i = 0; i < (int)index.size(); ++i) {
+	  index[i]->read(ls, edge);
+	}
+      }
+    }
+
+    bool isResolver() const {
+      return inverter.get() != 0;
+    }
+
+    typename Graph::Edge resolve(std::istream& is) {
+      return inverter->read(is);
+    } 
+
+  private:
+
+    typedef std::map<std::string, ReaderBase<Item>*> MapReaders;
+    MapReaders readers;
+   
+    Graph& graph;   
+    std::string id;
+    SkipReader<Item, DefaultSkipper> skipper;
+
+    std::auto_ptr<InverterBase<Item> > inverter;
+    std::auto_ptr<ResolverReaderBase<typename Graph::Node> > nodeResolver;
+  };
+
+
+  /// \e
+  template <typename _Traits = DefaultReaderTraits>
+  class AttributeReader : public CommonSectionReaderBase {
+    typedef CommonSectionReaderBase Parent;
+    typedef _Traits Traits; 
+  public:
+    /// \e
+    AttributeReader(LemonReader& _reader, 
+		    const std::string& _id = std::string()) : id(_id) {
+      _reader.attach(*this);
+    }
+
+    /// \e
+    virtual ~AttributeReader() {
+      for (typename Readers::iterator it = readers.begin(); 
+	   it != readers.end(); ++it) {
+	delete it->second;
+      }
+    }
+
+  private:
+    AttributeReader(const AttributeReader&);
+    void operator=(AttributeReader&);
+
+  public:
+    /// \e
+    template <typename Value>
+    AttributeReader& readAttribute(const std::string& id, Value& value) {
+      return readAttribute<typename Traits::template Reader<Value> >
+	(id, value);
+    }
+
+    /// \e
+    template <typename Reader, typename Value>
+    AttributeReader& readAttribute(const std::string& name, Value& value,
+				   const Reader& reader = Reader()) {
+      if (readers.find(name) != readers.end()) {
+	ErrorMessage msg;
+	msg << "Multiple read rule for attribute: " << name;
+	throw IOParameterError(msg.message());
+      }
+      readers.insert(make_pair(name, new ValueReader<Value, Reader>
+      			       (value, reader)));
+      return *this;
+    }
+
+    /// \e
+    bool header(const std::string& line) {
+      std::istringstream ls(line);
+      std::string command;
+      std::string name;
+      ls >> command >> name;
+      return command == "@attributes" && name == id;
+    }
+
+    /// \e
+    void read(std::istream& is) {
+      std::string line;
+      while (getline(is, line)) {
+	std::istringstream ls(line);
+	std::string id;
+	ls >> id;
+	typename Readers::iterator it = readers.find(id);
+	if (it != readers.end()) {
+	  it->second->read(ls);
+	}
+      }
+    }    
+
+  private:
+    std::string id;
+
+    typedef std::map<std::string, ValueReaderBase*> Readers;
+    Readers readers;
+  
+  };
+
+  template <typename _Graph>
+  class NodeReader : public CommonSectionReaderBase {
+    typedef CommonSectionReaderBase Parent;
+    typedef _Graph Graph;
+    typedef typename Graph::Node Item;
+  public:
+    
+    template <typename Resolver>
+    NodeReader(LemonReader& _reader, const Resolver& _resolver, 
+	       const std::string& _id = std::string()) 
+      : id(_id), resolver(new ResolverReader<typename Graph::Node, Resolver>
+		     (_resolver)) {
+      _reader.attach(*this);
+    } 
+
+    virtual ~NodeReader() {}
+
+  private:
+    NodeReader(const NodeReader&);
+    void operator=(const NodeReader&);
+
+  public:
+
+    void readNode(const std::string& name, Item& item) {
+      if (readers.find(name) != readers.end()) {
+	ErrorMessage msg;
+	msg << "Multiple read rule for node: " << name;
+	throw IOParameterError(msg.message());
+      }
+      readers.insert(make_pair(name, &item));
+    }
+
+    virtual bool header(const std::string& line) {
+      std::istringstream ls(line);
+      std::string command;
+      std::string name;
+      ls >> command >> name;
+      return command == "@nodes" && name == id;
+    }
+
+    virtual void read(std::istream& is) {
+      std::string line;
+      while (getline(is, line)) {
+	std::istringstream ls(line);
+	std::string id;
+	ls >> id;
+	typename ItemReaders::iterator it = readers.find(id);
+	if (it != readers.end()) {
+	  *(it->second) = resolver->resolve(ls); 
+	}	
+      }
+    }
+    
+  private:
+
+    std::string id;
+
+    typedef std::map<std::string, Item*> ItemReaders;
+    ItemReaders readers;
+    std::auto_ptr<ResolverReaderBase<Item> > resolver;
+  };
+
+  template <typename _Graph>
+  class EdgeReader : public CommonSectionReaderBase {
+    typedef CommonSectionReaderBase Parent;
+    typedef _Graph Graph;
+    typedef typename Graph::Edge Item;
+  public:
+    
+    template <typename Resolver>
+    EdgeReader(LemonReader& _reader, const Resolver& _resolver, 
+	       const std::string& _id = std::string()) 
+      : id(_id), resolver(new ResolverReader<typename Graph::Node, Resolver>
+		     (_resolver)) {
+      _reader.attach(*this);
+    } 
+
+    virtual ~EdgeReader() {}
+  private:
+    EdgeReader(const EdgeReader&);
+    void operator=(const EdgeReader&);
+
+  public:
+
+    void readEdge(const std::string& name, Item& item) {
+      if (readers.find(name) != readers.end()) {
+	ErrorMessage msg;
+	msg << "Multiple read rule for edge: " << name;
+	throw IOParameterError(msg.message());
+      }
+      readers.insert(make_pair(name, &item));
+    }
+
+
+    virtual bool header(const std::string& line) {
+      std::istringstream ls(line);
+      std::string command;
+      std::string name;
+      ls >> command >> name;
+      return command == "@nodes" && name == id;
+    }
+
+    virtual void read(std::istream& is) {
+      std::string line;
+      while (getline(is, line)) {
+	std::istringstream ls(line);
+	std::string id;
+	ls >> id;
+	typename ItemReaders::iterator it = readers.find(id);
+	if (it != readers.end()) {
+	  *(it->second) = resolver->resolve(ls); 
+	}	
+      }
+    }
+    
+  private:
+
+    std::string id;
+
+    typedef std::map<std::string, Item*> ItemReaders;
+    ItemReaders readers;
+    std::auto_ptr<ResolverReaderBase<Item> > resolver;
+  };
+
+  /// \e
+  class PrintReader : public LemonReader::SectionReader {
+    typedef LemonReader::SectionReader Parent;
+  public:
+
+    /// \e
+    PrintReader(LemonReader& reader) {
+      reader.attach(*this);
+    }
+
+    /// \e
+    bool header(const std::string& line) {
+      std::cout << "Asked header: " << line << std::endl; 
+      return true;
+    }
+
+    /// \e
+    void read(std::istream& is) {
+      std::string line;
+      while (std::getline(is, line)) {
+	std::cout << line << std::endl;
+      }
+    }
+  
+  };
+
+  /// @}
+}
+#endif
