/***************************************************************************

    supportware
    Copyright (C) 2001-2008 by c.holzheuer
    c.holzheuer@sourceworx.org

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

***************************************************************************/


#include <ddconfig.h>
#include <ddtoken.h>
#include <stdexcept>

/**
	Default Constructor.
*/

ddconfigoptions::ddconfigoptions()
: ddstringmap()
{
}

/**
	Destructor.
*/

ddconfigoptions::~ddconfigoptions()
{
}


/**
	Returns.
*/

void ddconfigoptions::create( int argc, char** argv )
{
	clear();
  for( int i=1; i<argc; i++ )
	{
		ddstring option =  ddstring( argv[i++] );
    // fetch option value if possible
		if( i<argc && option.size() > 0 && option[0] == '-' )
			set_option( option, ddstring( argv[i] ) );
	}
	
}


/**
	Returns.
*/

void ddconfigoptions::sync( ddconfig& config, const ddstring& sectionname )
{
	ddconfigsection& section =  config[ sectionname ];
	ddconfigoptions::const_iterator pos = begin();
  for( ; pos != end(); ++pos )
		section[ (*pos).first ] = (*pos).second;
}


/**
	Returns.
*/

void ddconfigoptions::set_option( const ddstring& optionkey, const ddstring& value )
{
	ddstring& key =  _aliases[ optionkey ];
  if( !key.empty() )
		(*this)[key] = value;
	else
		throw runtime_error( "ddconfigoptions::set_option: unknown option: " +  optionkey );

}


/**
	Returns.
*/

void ddconfigoptions::add_option( const ddstring& key, const ddstring& skey, const ddstring& lkey, const ddstring& defval )
{
   _aliases[ skey ]  = key;
   _aliases[ lkey ]  = key;
   (*this)[ key ] = defval;
}


/**
	Dumps all fields for debugging purposes.
	@see ddbaseobject
*/

void ddconfigoptions::dump() const
{
	ddstringmap::const_iterator pos = _aliases.begin();
  cout << "configoptions:" << endl;
  for( ; pos != _aliases.end(); ++pos )
		cout <<  "key: <" << (*pos).first << "> value: <" << (*pos).second << ">" << endl;
	pos = begin();
	for( ; pos != end(); ++pos )
		cout << "selfkey: <" << (*pos).first << "> selfvalue: <" << (*pos).second << ">" << endl;
  cout << "\n\n" << endl;

}


/***************************************************************************

    supportware
    Copyright (C) 2001-2008 by c.holzheuer
    c.holzheuer@sourceworx.org

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

***************************************************************************/

/**
	Default constructor.
*/


ddconfigparser::ddconfigparser()
:	_curtok(0), _peek(false), _lineno(1)
{
	for( size_t i=0; i<ddtoken::dd_token_size; ++i )
	{
		_tokenmap[ddtoken::id[i]] = i;
	}
}


/**
	Copy constructor.
*/

ddconfigparser::ddconfigparser( const ddconfigparser& src )
: ddbaseobject()
{
	*this = src;
}


/**
	Assignment operator. not done yet.
*/

ddconfigparser& ddconfigparser::operator=( const ddconfigparser& src )
{
	if( this == &src )
		return *this;
	throw runtime_error( "ddconfigparser::operator=: not done yet!" );
	return *this;
}


/**
	Destructor.
*/

ddconfigparser::~ddconfigparser()
{

}



/**
	Destructor.
*/

bool ddconfigparser::parse_config( ddconfig* target, const ddstring& filename, const ddstring& base )
{
	// pass 0 : reset all
	_target = target;
			
	// pass 1: read primary file, parse includes & remove comments
	scan_includes( _txt, filename );
	
	// include dran-pfuschen
	if( !base.empty() )
	{
		ddstring basefile;
		basefile.from_file( base );
		_txt = basefile + _txt;
	}
	
	_input.str( _txt );
		
	// pass 2: parse src
	while( _input  )
		parse_section();

	return true;
	
}


/**
	Destructor.
*/

bool ddconfigparser::parse_section()
{
	size_t token = get_token();
  // code is done...
	if( token == ddtoken::t_nop )
		return false;

	// section : "name"
  // PFUSCH
	if( token != ddtoken::t_section && token != ddtoken::t_site && token != ddtoken::t_table && token != ddtoken::t_form && token != ddtoken::t_tagblock )
 		create_error( "'section', 'table' or 'domain' expected!" );
  ddstring type = _entrystack.top().value;
	scan_token( ddtoken::t_colon );
	scan_token( ddtoken::t_value );
	ddstring name = _entrystack.top().value;

	//  begin section body
	scan_token( ddtoken::t_open_brace3 );
	_current =  _target->add_section( type, name );
	while( (token = peek_token() ) != ddtoken::t_close_brace3 )
		parse_entry();
	
	// section is done
	scan_token( ddtoken::t_close_brace3 );
	return true;
}


/**
	Destructor.
*/

void ddconfigparser::parse_entry()
{

  scan_token( ddtoken::t_id );
	ddstring name = _entrystack.top().value;
	scan_token( ddtoken::t_assign );
  scan_token( ddtoken::t_value );
	ddstring value = _entrystack.top().value;
  scan_token( ddtoken::t_semicolon );
	(*_current).add_by_key( name, value );
}



/**
	Reads a file into a ddstring.
	@param target	the target ddstring.
	@param filenam the file to load.
*/

void ddconfigparser::read_file( ddstring& target, const ddstring& filename )
{
	_sources.insert( filename );
	if( target.from_file( filename ) < 0 )
		create_error("ddconfigparser::include: read error!");
	
}


/**
	FIX!!
	Buggy trash to  include a file.
*/

void ddconfigparser::include( ddstring& target, size_t from, size_t count, const ddstring& filename )
{ 		
	if( _sources.count( filename ) )
	{
		target.replace( from, count, "" );
	}
	else
	{
		ddstring txt;
		read_file( txt, filename );		
		target.replace( from, count, txt );			
	}	
}


/**
	FIX!!
	Buggy trash to load include files.
*/

	
void ddconfigparser::scan_includes( ddstring& target, const ddstring& filename )
{
	// init again
	_curtok = 0;
	_peek = false;
	_lineno = 1;
	_tmp = "";
  _entrystack.clear();

	read_file( target, filename );
	
	size_t pos=ddstring::npos;
	
	/**
	FIX! this searches in ddstring literals also!!!
	*/
	
	while( (pos=target.find( "use: " )) != ddstring::npos )
	{
		size_t end = target.find( ';', pos+5 );
		if( end != ddstring::npos )
		{
			ddstring fname = target.substr( pos+5, end-pos-5 );		
			include( target, pos, end-pos+1, fname );
		}
		else
		{
			create_error("ddconfigparser::include: invalid include!");
		}
	}
}


/**
	Internal function to fetch the next token from the input stream.
	Returns the current token, if any. Otherwise, get_token() is called.
	@return the token
	@see ddopcode
	@see get_token()	
*/

size_t ddconfigparser::peek_token()
{
	if( _peek )
		return _curtok;
	get_token();
	_peek = true;
	return _curtok;
}


/**
	Internal function to confirm an expected token. If the next token in the
	token stream doesn't match, a fatal error can be created.
	@param	token the token to read.
	@param	error	create error on token mismatch (defaults to true)
	@see 		create_error
*/


bool ddconfigparser::scan_token( size_t token, bool create_err )
{
	bool result = ( get_token() == token );
	if( !result && create_err )
	{
		ddstring error = ddstring("found: '") + ddstring(ddtoken::id[_curtok]) + "'";
		create_error( error + ddstring(" expected: '") + ddstring(ddtoken::id[token]) + "'" );
	}
	return result;
}


/**
	Skip blank chars ( \n \r \t ' ' ) in the input stream.
*/

void ddconfigparser::scan_blank()
{	
  do
	{
		if( _currentchar=='\n' )
			 _lineno++;
		if( !isspace( _currentchar )  )
			return;
	}
	while( _input.get( _currentchar )  );	
}


/**
	Internal function to fetch the next character from the input stream.
	C/C++ comments are skipped.
	@param move if true, the input stream pointer is moved one position.
	@return the character
*/

char ddconfigparser::get_char()
{
	// try to skip C/C++ comments
   
	while( _input.get( _currentchar ) )
	{
		if( _currentchar != '/' ) 		
			break;

		char peekchar;  
		_input.get( peekchar );
       
		if( peekchar == '/' )
		{
			// skip cpp-sytle comment
		  _input.ignore( _txt.size(), '\n' );
		  _lineno++;
		}
		else if( peekchar== '*' ) 
		{	
			char lastchar=0;
			// skip c-style comment          
			while( _input.get( peekchar ) ) 
			{
            
				if( peekchar == '\n' )
					 _lineno++;
				
				if( peekchar == '/' &&  lastchar == '*' )
					break;
				lastchar = peekchar;			
			}		

		}
		// es war kein Kommentar, also sowas wie /= ...
		else
		{
      // Zeichen sichern
      //_input.put_back( peekchar );
      _input.unget();
			break;
		}
    
	}	

  return _currentchar;		

}



/**
	Internal function to fetch the next token from the input stream.
	@return the token
	@see ddopcode
*/

size_t ddconfigparser::get_token()
{	
	if( _peek )
	{
		_peek = false;
		return _curtok;
	}
	
   get_char();
	scan_blank();

	// test for ids
	if( isalpha( _currentchar	 ) || _currentchar == '_' )
		_curtok = scan_identifier();
	// test for int & double
	else if( isdigit( _currentchar ) )
		_curtok = scan_numeric_literal();
	// test for ddstrings
	else if( _currentchar == '\'' || _currentchar == '"' )
		_curtok = scan_string_literal();											
	// must be operator
	else
		_curtok = scan_operator();
	return _curtok;
}

/**
	Internal function to scan an identifier.
*/

size_t ddconfigparser::scan_identifier()
{
   do
   {
		 _tmp += _currentchar;
		 get_char();
   }
	//while( isalnum( _currentchar ) || _currentchar == '_' );
	// neu:
	// - und . erlauben
	while( isalnum( _currentchar ) || _currentchar == '_' || _currentchar == '.' || _currentchar == '-' );
	
	 // now, we are behind
	 _input.unget();
	 
	if( _tmp == DDSTRTRUE || _tmp == DDSTRFALSE )
	{
		create_entry( ddtoken::t_bool );
		return ddtoken::t_value;
	}
	// lookup identifier: maybe its a keyword or type.
	size_t token = ddtoken::t_id;
	ddmapindex::iterator pos = _tokenmap.find( _tmp );
	if( pos != _tokenmap.end() )
		token = (*pos).second;

		// store real token
	create_entry( token );

	
	// fake token as type
	switch( token )
	{
	 	case ddtoken::t_void :
		case ddtoken::t_ddstring :
		case ddtoken::t_int  :
		case ddtoken::t_double :
		case ddtoken::t_bool :

		case ddtoken::t_seq :
		case ddtoken::t_date :
		case ddtoken::t_currency :
		case ddtoken::t_page :
		// ?? FIX!
		//case ddtoken::t_system :
		//case ddtoken::t_module :
		//case ddtoken::t_site :

			//return ddtoken::t_id;
		return ddtoken::t_type;
	}

	return token;

}
/**
	Internal function to scan a string literal.
*/

size_t ddconfigparser::scan_string_literal()
{ 
	
	char delim = _currentchar;
  //while( get_char() != delim )
	while( _input.get( _currentchar ) )
	{
		if( _currentchar == delim )
			break;
		_tmp += _currentchar;			
  }	
		
	create_entry( ddtoken::t_ddstring );	
	return ddtoken::t_value;
}


/**
	Internal function to scan a numeric literal.
*/

size_t ddconfigparser::scan_numeric_literal()
{ 
	bool dot=false;
	while( isdigit( _currentchar ) || _currentchar == '.' )
	{
	  _tmp +=_currentchar;				
		if( get_char() == '.' )
		{
			if( dot )
				create_error("double dot in numeric literal");
			dot=true;
		}
	}
  // now, we are behind
  _input.unget();
	
	if( dot )
		create_entry( ddtoken::t_double );
	else
		create_entry( ddtoken::t_int );
	
	return ddtoken::t_value;			
}



/**
	Internal function to scan an operator: + - * etc.
*/

size_t ddconfigparser::scan_operator()
{ 

	_tmp += _currentchar;
	// += -= *= /= %= &= |= <= >= != << >> ++ -- 
   	size_t token = ddtoken::t_nop;
	ddstring tmp = _tmp + get_char();
	ddmapindex::iterator pos = _tokenmap.find( tmp );	

  // found valid operator
	if( pos != _tokenmap.end() )
	{
		_tmp = "";
		get_char();
		return (*pos).second;
	}
	else
	{
		_input.unget();
	}
	
	pos = _tokenmap.find( _tmp );	
	
	// found valid operator
	if( pos != _tokenmap.end() )
		token = (*pos).second;		
	_tmp="";
  
	return token;
}



/**
	This internal function stores the current token in the token list.
	@param	type the token type.
*/

void ddconfigparser::create_entry( size_t type )	
{		
	if( !_tmp.empty() )
		_entrystack.push( ddparseentry( type, _lineno, _tmp ) );
	_tmp="";
}		
		
			
/**
	Creates an error message and throws an exception.
	@param	msg	the error message.
	@param	line	the error line
*/

void ddconfigparser::create_error( const ddstring& text, size_t line )
{	
	ddstring txt = " parse error in line "+ ddstrutil::from_int( line );
	// FIX! this doesnt work!
	if( _currentchar != '\n' ) //avoid newline character
	{
		txt +=  " before '";
		txt +=  _currentchar;
		txt +=  "' ";
	}
	if( !text.empty() )
		txt += ": " + text;
	//log_info( txt );
	throw invalid_argument( txt );
}	

/**
	Creates an error message for the currently parsed line and throws an exception.
	@param	msg the error message.
*/

void ddconfigparser::create_error( const ddstring& msg )
{
	create_error( msg, _lineno );
}



















/***************************************************************************

    supportware
    Copyright (C) 2001-2008 by c.holzheuer
    c.holzheuer@sourceworx.org

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

***************************************************************************/

/**
	Default constructor.
*/


ddconfigparser_neu::ddconfigparser_neu()
:	_curtok(0), _peek(false), _lineno(1)
{
	for( size_t i=0; i<ddtoken::dd_token_size; ++i )
	{
		_tokenmap[ddtoken::id[i]] = i;
	}
}


/**
	Copy constructor.
*/

ddconfigparser_neu::ddconfigparser_neu( const ddconfigparser_neu& src )
: ddbaseobject()
{
	*this = src;
}


/**
	Assignment operator. not done yet.
*/

ddconfigparser_neu& ddconfigparser_neu::operator=( const ddconfigparser_neu& src )
{
	if( this == &src )
		return *this;
	throw runtime_error( "ddconfigparser_neu::operator=: not done yet!" );
	return *this;
}


/**
	Destructor.
*/

ddconfigparser_neu::~ddconfigparser_neu()
{

}



/**
	Destructor.
*/

bool ddconfigparser_neu::parse_config( ddconfig* target, const ddstring& filename, const ddstring& base )
{
	// pass 0 : reset all
	_target = target;
			
	// pass 1: read primary file, parse includes & remove comments
	scan_includes( _txt, filename );
	
	// include dran-pfuschen
	if( !base.empty() )
	{
		ddstring basefile;
		basefile.from_file( base );
		_txt = basefile + _txt;
	}
	
	_input.str( _txt );
		
	// pass 2: parse src
	while( _input  )
		parse_section();

	return true;
	
}


/**
	Destructor.
*/

bool ddconfigparser_neu::parse_section()
{
	size_t token = get_token();
  // code is done...
	if( token == ddtoken::t_nop )
		return false;

	// section : "name"
  // PFUSCH
	if( token != ddtoken::t_section && token != ddtoken::t_site && token != ddtoken::t_table && token != ddtoken::t_form && token != ddtoken::t_tagblock )
 		create_error( "'section', 'table' or 'domain' expected!" );
  ddstring type = _entrystack.top().value;
	scan_token( ddtoken::t_colon );
	scan_token( ddtoken::t_value );
	ddstring name = _entrystack.top().value;

	//  begin section body
	scan_token( ddtoken::t_open_brace3 );
	_current =  _target->add_section( type, name );
	while( (token = peek_token() ) != ddtoken::t_close_brace3 )
		parse_entry();
	
	// section is done
	scan_token( ddtoken::t_close_brace3 );
	return true;
}


/**
	Destructor.
*/

void ddconfigparser_neu::parse_entry()
{

  scan_token( ddtoken::t_id );
	ddstring name = _entrystack.top().value;
	scan_token( ddtoken::t_assign );
  scan_token( ddtoken::t_value );
	ddstring value = _entrystack.top().value;
  scan_token( ddtoken::t_semicolon );
	(*_current).add_by_key( name, value );
}



/**
	Reads a file into a ddstring.
	@param target	the target ddstring.
	@param filenam the file to load.
*/

void ddconfigparser_neu::read_file( ddstring& target, const ddstring& filename )
{
	_sources.insert( filename );
	if( target.from_file( filename ) < 0 )
		create_error("ddconfigparser_neu::include: read error!");
	
}


/**
	FIX!!
	Buggy trash to  include a file.
*/

void ddconfigparser_neu::include( ddstring& target, size_t from, size_t count, const ddstring& filename )
{ 		
	if( _sources.count( filename ) )
	{
		target.replace( from, count, "" );
	}
	else
	{
		ddstring txt;
		read_file( txt, filename );		
		target.replace( from, count, txt );			
	}	
}


/**
	FIX!!
	Buggy trash to load include files.
*/

	
void ddconfigparser_neu::scan_includes( ddstring& target, const ddstring& filename )
{
	// init again
	_curtok = 0;
	_peek = false;
	_lineno = 1;
	_tmp = "";
  _entrystack.clear();

	read_file( target, filename );
	
	size_t pos=ddstring::npos;
	
	/**
	FIX! this searches in ddstring literals also!!!
	*/
	
	while( (pos=target.find( "use: " )) != ddstring::npos )
	{
		size_t end = target.find( ';', pos+5 );
		if( end != ddstring::npos )
		{
			ddstring fname = target.substr( pos+5, end-pos-5 );		
			include( target, pos, end-pos+1, fname );
		}
		else
		{
			create_error("ddconfigparser_neu::include: invalid include!");
		}
	}
}


/**
	Internal function to fetch the next token from the input stream.
	Returns the current token, if any. Otherwise, get_token() is called.
	@return the token
	@see ddopcode
	@see get_token()	
*/

size_t ddconfigparser_neu::peek_token()
{
	if( _peek )
		return _curtok;
	get_token();
	_peek = true;
	return _curtok;
}


/**
	Internal function to confirm an expected token. If the next token in the
	token stream doesn't match, a fatal error can be created.
	@param	token the token to read.
	@param	error	create error on token mismatch (defaults to true)
	@see 		create_error
*/


bool ddconfigparser_neu::scan_token( size_t token, bool create_err )
{
	bool result = ( get_token() == token );
	if( !result && create_err )
	{
		ddstring error = ddstring("found: '") + ddstring(ddtoken::id[_curtok]) + "'";
		create_error( error + ddstring(" expected: '") + ddstring(ddtoken::id[token]) + "'" );
	}
	return result;
}


/**
	Skip blank chars ( \n \r \t ' ' ) in the input stream.
*/

void ddconfigparser_neu::scan_blank()
{	
  do
	{
		if( _currentchar=='\n' )
			 _lineno++;
		if( !isspace( _currentchar )  )
			return;
	}
	while( _input.get( _currentchar )  );	
}


/**
	Internal function to fetch the next character from the input stream.
	C/C++ comments are skipped.
	@param move if true, the input stream pointer is moved one position.
	@return the character
*/

char ddconfigparser_neu::get_char()
{
	// try to skip C/C++ comments
   
	while( _input.get( _currentchar ) )
	{
		if( _currentchar != '/' ) 		
			break;

		char peekchar;  
		_input.get( peekchar );
       
		if( peekchar == '/' )
		{
			// skip cpp-sytle comment
		  _input.ignore( _txt.size(), '\n' );
		  _lineno++;
		}
		else if( peekchar== '*' ) 
		{	
			char lastchar=0;
			// skip c-style comment          
			while( _input.get( peekchar ) ) 
			{
            
				if( peekchar == '\n' )
					 _lineno++;
				
				if( peekchar == '/' &&  lastchar == '*' )
					break;
				lastchar = peekchar;			
			}		

		}
		// es war kein Kommentar, also sowas wie /= ...
		else
		{
      // Zeichen sichern
      //_input.put_back( peekchar );
      _input.unget();
			break;
		}
    
	}	

  return _currentchar;		

}



/**
	Internal function to fetch the next token from the input stream.
	@return the token
	@see ddopcode
*/

size_t ddconfigparser_neu::get_token()
{	
	if( _peek )
	{
		_peek = false;
		return _curtok;
	}
	
   get_char();
	scan_blank();

	// test for ids
	if( isalpha( _currentchar	 ) || _currentchar == '_' )
		_curtok = scan_identifier();
	// test for int & double
	else if( isdigit( _currentchar ) )
		_curtok = scan_numeric_literal();
	// test for ddstrings
	else if( _currentchar == '\'' || _currentchar == '"' )
		_curtok = scan_string_literal();											
	// must be operator
	else
		_curtok = scan_operator();
	return _curtok;
}

/**
	Internal function to scan an identifier.
*/

size_t ddconfigparser_neu::scan_identifier()
{
   do
   {
		 _tmp += _currentchar;
		 get_char();
   }
	while( isalnum( _currentchar ) || _currentchar == '_' );
	
	 // now, we are behind
	 _input.unget();
	 
	if( _tmp == DDSTRTRUE || _tmp == DDSTRFALSE )
	{
		create_entry( ddtoken::t_bool );
		return ddtoken::t_value;
	}
	// lookup identifier: maybe its a keyword or type.
	size_t token = ddtoken::t_id;
	ddmapindex::iterator pos = _tokenmap.find( _tmp );
	if( pos != _tokenmap.end() )
		token = (*pos).second;

		// store real token
	create_entry( token );

	
	// fake token as type
	switch( token )
	{
	 	case ddtoken::t_void :
		case ddtoken::t_ddstring :
		case ddtoken::t_int  :
		case ddtoken::t_double :
		case ddtoken::t_bool :

		case ddtoken::t_seq :
		case ddtoken::t_date :
		case ddtoken::t_currency :
		case ddtoken::t_page :
		// ?? FIX!
		//case ddtoken::t_system :
		//case ddtoken::t_module :
		//case ddtoken::t_site :

			//return ddtoken::t_id;
		return ddtoken::t_type;
	}

	return token;

}
/**
	Internal function to scan a string literal.
*/

size_t ddconfigparser_neu::scan_string_literal()
{ 
	
	char delim = _currentchar;
  //while( get_char() != delim )
	while( _input.get( _currentchar ) )
	{
		if( _currentchar == delim )
			break;
		_tmp += _currentchar;			
  }	
		
	create_entry( ddtoken::t_ddstring );	
	return ddtoken::t_value;
}


/**
	Internal function to scan a numeric literal.
*/

size_t ddconfigparser_neu::scan_numeric_literal()
{ 
	bool dot=false;
	while( isdigit( _currentchar ) || _currentchar == '.' )
	{
	  _tmp +=_currentchar;				
		if( get_char() == '.' )
		{
			if( dot )
				create_error("double dot in numeric literal");
			dot=true;
		}
	}
  // now, we are behind
  _input.unget();
	
	if( dot )
		create_entry( ddtoken::t_double );
	else
		create_entry( ddtoken::t_int );
	
	return ddtoken::t_value;			
}



/**
	Internal function to scan an operator: + - * etc.
*/

size_t ddconfigparser_neu::scan_operator()
{ 

	_tmp += _currentchar;
	// += -= *= /= %= &= |= <= >= != << >> ++ -- 
   	size_t token = ddtoken::t_nop;
	ddstring tmp = _tmp + get_char();
	ddmapindex::iterator pos = _tokenmap.find( tmp );	

  // found valid operator
	if( pos != _tokenmap.end() )
	{
		_tmp = "";
		get_char();
		return (*pos).second;
	}
	else
	{
		_input.unget();
	}
	
	pos = _tokenmap.find( _tmp );	
	
	// found valid operator
	if( pos != _tokenmap.end() )
		token = (*pos).second;		
	_tmp="";
  
	return token;
}



/**
	This internal function stores the current token in the token list.
	@param	type the token type.
*/

void ddconfigparser_neu::create_entry( size_t type )	
{		
	if( !_tmp.empty() )
		_entrystack.push( ddparseentry( type, _lineno, _tmp ) );
	_tmp="";
}		
		
			
/**
	Creates an error message and throws an exception.
	@param	msg	the error message.
	@param	line	the error line
*/

void ddconfigparser_neu::create_error( const ddstring& text, size_t line )
{	
	ddstring txt = " parse error in line "+ ddstrutil::from_int( line );
	// FIX! this doesnt work!
	if( _currentchar != '\n' ) //avoid newline character
	{
		txt +=  " before '";
		txt +=  _currentchar;
		txt +=  "' ";
	}
	if( !text.empty() )
		txt += ": " + text;
	//log_info( txt );
	throw invalid_argument( txt );
}	

/**
	Creates an error message for the currently parsed line and throws an exception.
	@param	msg the error message.
*/

void ddconfigparser_neu::create_error( const ddstring& msg )
{
	create_error( msg, _lineno );
}












































/***************************************************************************

    supportware
    Copyright (C) 2001-2008 by c.holzheuer
    c.holzheuer@sourceworx.org

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

***************************************************************************/


/**
	Default Constructor.
*/

ddconfigsection::ddconfigsection()
{
}


/**
	Standard Constructor.
*/

ddconfigsection::ddconfigsection( const ddstring& type, const ddstring& name )
: _type( type )
{
	set_name( name );
}


/**
	Copy constructor.
*/

ddconfigsection::ddconfigsection( const ddconfigsection& src )
{
	*this = src;
}


/**
	Assignment operator.
*/

ddconfigsection& ddconfigsection::operator=( const ddconfigsection& src )
{
	if( this == &src )
		return *this;
	_data = src._data;
	_index = src._index;
	_type = src._type;
	_name = src._name;
	return *this;
}
	
/**
	Destructor.
*/

ddconfigsection::~ddconfigsection()
{
}


/**
	@Returns einen String-Eintrag mit dem Schlüssel 'key' zurück. Falls dieser fehlt,
	wird 'defaultvalue' gesetzt und zurückgegeben.
*/

ddstring& ddconfigsection::get_entry( const ddstring& key, const ddstring& defaultvalue )
{
	ddstring& result  = (*this)[key];
	if( result.empty() )
		(*this)[key] = defaultvalue;
	return (*this)[key];
}


/**
	@Returns den Eintrag mit Schlüssel 'key' als Bool.
*/

bool ddconfigsection::get_bool( const ddstring& key, bool defaultvalue )
{
	ddstring tmp = get_entry( key );
  if( tmp.empty() )
		return defaultvalue;
	return tmp.as_bool();
}


/**
	@Returns den Eintrag mit Schlüssel 'key' als Int.
*/

int ddconfigsection::get_int( const ddstring& key, int defaultvalue )
{
   ddstring tmp = get_entry( key);
   if( tmp.empty() )
		 return defaultvalue;
   return tmp.as_int();
}


/**
	@Returns den Eintrag mit Schlüssel 'key' als double.
*/

double ddconfigsection::get_double( const ddstring& key, double defaultvalue )
{
	ddstring tmp = get_entry( key);
	if( tmp.empty() )
		return defaultvalue;
	return tmp.as_double();
}


/**
	@Returns den Type: "section" oder "domain"
*/

const ddstring& ddconfigsection::get_type()
{
	return _type;
}


/**
	Dump-ed diese section.
*/

void  ddconfigsection::dump() const
{
	cout << "Configsection: " << get_name() << ": " << size() << endl;
	for( int i=0; i<size(); ++i )
		cout << key_of(i) << "=" << (*this)[i] << endl;
}


/***************************************************************************

    supportware
    Copyright (C) 2001-2008 by c.holzheuer
    c.holzheuer@sourceworx.org

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

***************************************************************************/


/**
	Default Constructor.
*/

ddconfig::ddconfig()
: ddmaprow<ddconfigsection>()
{
}


/**
	Destructor.
*/

ddconfig::~ddconfig()
{
}


/**
	Load the configfile "filename".
*/

bool ddconfig::load( const ddstring& filename, const ddstring& base )
{
  set_name( filename );
	return _configparser.parse_config( this, filename, base );
}


/**
	Add a new configsection "name".
*/

ddconfigsection* ddconfig::add_section( const ddstring& type, const ddstring& name )
{
	add_by_key( name, ddconfigsection( type, name ) );
	return &( (*this)[name] );
}


/**
	Dump this config.
*/

void  ddconfig::dump() const
{
	cout << "ddconfig: " << get_name() << endl;
  for( size_t i=0; i<_data.size(); i++ )
		_data[i].dump();
}

