//! @file
//! @author Claes Nasten <pekdon{@}pekdon{.}net
//! @date 2005-05-21
//! @brief Configuration file parser.
//! Configuration file parser with file inclusion support and command
//! output parsing support.
//! The format beeing parsed:
//! $var = "value"
//! !include = "file to include"
//! section = "name" {
//!   key = "name" {
//!     value = "$var"
//!   }
//! }

//
// Copyright (C) 2005 Claes Nasten <pekdon{@}pekdon{.}net>
//
// This program is licensed under the GNU GPL.
// See the LICENSE file for more information.
//

#ifndef _CFG_PARSER_HH_
#define _CFG_PARSER_HH_

#include "CfgParserKey.hh"
#include "CfgParserSource.hh"

#include <list>
#include <map>
#include <set>
#include <string>
#include <iostream>
#include <cstdlib>

//! @brief Configuration file parser.
class CfgParser {
public:
  //! @brief Entry in parsed data structure.
  class Entry {
  public:
    Entry (const std::string &or_source_name, int i_line,
           const std::string &or_name, const std::string &or_value);
    ~Entry (void);

    //! @brief Returns the name.
    const std::string &get_name (void) const { return m_o_name; }
    //! @brief Returns the value.
    const std::string &get_value (void) const { return m_o_value; }
    //! @brief Returns the linenumber in the source this was parsed.
    int get_line (void) const { return m_i_line; }
    //! @brief Returns the name of the source this was parsed.
    const std::string &get_source_name (void) const { return m_or_source_name; }

    Entry *add_entry (const std::string &or_source_name, int i_line,
                      const std::string &or_name, const std::string &or_value);

    //! @brief Returns the next Entry.
    Entry *get_entry_next (void) { return m_op_entry_next; }
    //! @brief Returns the sub section.
    Entry *get_section (void) { return m_op_section; }
    Entry *get_section_next (void);

    //! @brief Sets the sub section.
    void set_section (Entry *op_section) { m_op_section = op_section; }

    Entry *find_entry (const std::string &or_name);
    Entry *find_section (const std::string &or_name);

    void parse_key_values (std::list<CfgParserKey*>::iterator o_begin,
                           std::list<CfgParserKey*>::iterator o_end);

    void print_tree (int level);
    void free_tree (void);

    //! @brief Matches Entry name agains op_rhs.
    bool operator== (const char *op_rhs) {
      return (strcasecmp (op_rhs, m_o_name.c_str()) == 0); }
    friend std::ostream &operator<< (std::ostream &or_stream,
                                     const CfgParser::Entry &or_entry);

  private:
    Entry *m_op_entry_next;
    Entry *m_op_section;

    std::string m_o_name;
    std::string m_o_value;

    int m_i_line;
    const std::string &m_or_source_name;
  };

  CfgParser (void);
  ~CfgParser (void);

  //! @brief Returns the root Entry node.
  Entry *get_entry_root (void) { return &m_o_root_entry; }

  bool parse (const std::string &or_src,
              CfgParserSource::Type i_type = CfgParserSource::SOURCE_FILE);


private:
  void parse_source_new (const std::string &or_name,
                         CfgParserSource::Type i_type);
  bool parse_name (std::string &or_buf);
  bool parse_value (CfgParserSource *op_source, std::string &or_value);
  void parse_entry_finish (std::string &or_buf, std::string &or_value);
  void parse_section_finish (std::string &or_buf, std::string &or_value);
  void parse_comment_line (CfgParserSource *op_source);
  void parse_comment_c (CfgParserSource *op_source);
  char parse_skip_blank (CfgParserSource *op_source);

  CfgParserSource *source_new (const std::string &or_name,
                               CfgParserSource::Type i_type);

  void variable_define (const std::string &or_name, const std::string &or_value);
  void variable_expand (std::string &or_string);

private:
  CfgParserSource *m_op_source;

  std::list<CfgParserSource*> m_o_source_list; //!< List of sources, for recursive parsing.
  std::list<std::string> m_o_source_name_list; //!< List of source names, to keep track of current source.
	std::set<std::string> m_o_source_name_set; //!< Set of source names, source of memory usage on long-going CfgParser objects.
  std::list<Entry*> m_o_entry_list; //!< List of Entries with sections, for recursive parsing.

  std::map<std::string, std::string> m_o_var_map; //!< Map of $VARS

  Entry m_o_root_entry; //!< Root Entry.
  Entry *m_op_entry; //!< Current Entry.

  static const std::string m_o_root_source_name; //!< Root Entry Source Name.
};

#endif // _CFG_PARSER_HH_


syntax highlighted by Code2HTML, v. 0.9.1