// Writer.cpp

//

// Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005 Matthew Flood

// See file AUTHORS for contact information

//

// This file is part of RudeConfig.

//

// RudeConfig 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, or (at your option)

// any later version.

// 

// RudeConfig is distributed in the hope that it will be useful,

// but WITHOUT ANY WARRANTY; without even the implied warranty of

// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the

// GNU General Public License for more details.

// 

// You should have received a copy of the GNU General Public License

// along with RudeConfig; (see COPYING) if not, write to the Free Software

// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA

// 02111-1307, USA.

//------------------------------------------------------------------------


#include "Writer.h"


#ifndef INCLUDED_File_H

#include "File.h"

#endif


#ifndef INCLUDED_Section_H

#include "Section.h"

#endif


#ifndef INCLUDED_KeyValue_H

#include "KeyValue.h"

#endif


#ifndef INCLUDED_Comment_H

#include "Comment.h"

#endif


#ifndef INCLUDED_WhiteSpace_H

#include "WhiteSpace.h"

#endif


#ifndef INCLUDED_CSTDLIB

#include <cstdlib>

#define INCLUDED_CSTDLIB

#endif


#ifndef INCLUDED_CCTYPE

#include <cctype>

#define INCLUDED_CCTYPE

#endif


#ifndef INCLUDED_IOSTREAM

#include <iostream>

#define INCLUDED_IOSTREAM

#endif


#ifndef INCLUDED_STRING

#include <string>

#define INCLUDED_STRING

#endif


using namespace std;

namespace rude{
namespace config{


Writer::Writer()
{

}

Writer::~Writer()
{

}


void Writer::visitFile(const File& configfile) const
{

}

void Writer::visitSection(const Section& configsection) const
{
		std::string name = configsection.getSectionName();
		
		// if there is a section name, we print it out [between brackets]

		//

		if(name != "")
		{
			if( configsection.isDeleted() )
			{
				if ( d_commentchar && d_preservedeleted )
				{
					*d_outputstream << d_commentchar << " ";
				}
				else
				{
					return;
				}
			}
		
			int position = 0;
			size_t location;

			// escape all backslashes

			//

			while( (location = name.find("\\", position)) != string::npos )
			{
				// location points right at the '\'

				name.insert(location,  "\\");
				position = (int) location + 2;
			}

			// escape all ']''s

			//

			while( (location = name.find("]", position)) != string::npos )
			{
				// location points right at the ']'

				name.insert(location,  "\\");
				position = (int) location + 2;
			}
			
			*d_outputstream << "[" << name << "]";
			
			// If the section name has a comment, we print it out after the section name

			//

			if(configsection.getSectionComment()[0] != 0 && d_commentchar)
			{
				*d_outputstream << "\t" << d_commentchar << configsection.getSectionComment();
			}

			// newline ends the section header

			//

			*d_outputstream << "\n";
		}
}

void Writer::visitComment(const Comment& comment) const
{
	if(d_preservecomments && d_commentchar && ( !comment.isDeleted() || d_preservedeleted ))
	{
			*d_outputstream << d_commentchar << comment.getComment() << "\n";
	}
}

void Writer::visitWhiteSpace(const WhiteSpace& whitespace) const
{
	if(d_preservewhitespace && ( !whitespace.isDeleted() || d_preservedeleted ))
	{
			*d_outputstream << whitespace.getWhiteSpace();
	}
}


void Writer::visitKeyValue(const KeyValue& dataline) const
{
	if(dataline.isDeleted() && ( !d_commentchar || !d_preservedeleted))
	{
		// Don't preserve deleted data when comments are null

		// or we don't want to preserve them

		return;
	}
	else
	{
		string key = dataline.getName();
		string value = dataline.getValue();
		string comment = dataline.getComment();

		string commentchar(1,d_commentchar);
		

		if(dataline.isDeleted())
		{
			// print the comment character

			//

			*d_outputstream << d_commentchar << " ";
		}

		if(key != "")
		{


			int position = 0;
			size_t location;

			// escape all backslashes

			//

			while( (location = key.find("\\", position)) != string::npos )
			{
				// location points right at the '\'

				key.insert(location,  "\\");
				position = (int) location + 2;
			}


			// escape comment characters

			// unless the comment character is a backslash, which we've already escaped....

			//

			if(d_commentchar && d_commentchar != '\\')
			{
				position = 0;

				while( (location = key.find(commentchar, position)) != string::npos )
				{
					// location points right at the '"'

					key.insert(location,  "\\");
					position = (int) location + 2;
				}
			}

			// escape all delimiters, unless the delimiter is a backslash or the same as the comment, god forbid.

			//

			//

			if(d_delimiter != '\\' && d_delimiter != d_commentchar)
			{
				if(d_delimiter)
				{
					string delimiter(1, d_delimiter);
					position = 0;

					while( (location = key.find(delimiter, position)) != string::npos )
					{
						// location points right at the '"'

						key.insert(location,  "\\");
						position = (int) location + 2;
					}
				}
				else
				{
					position = 0;

					while( (location = key.find("\t", position)) != string::npos )
					{
						// location points right at the '"'

						key.insert(location,  "\\");
						position = (int) location + 2;
					}
					
					position = 0;

					while( (location = key.find(" ", position)) != string::npos )
					{
						// location points right at the '"'

						key.insert(location,  "\\");
						position = (int) location + 2;
					}					

				}				
			}

			// print the key

			//

			*d_outputstream << key;
		}

		if(value != "")
		{
			// print out the delimiter

			//

			*d_outputstream  << " " << ( d_delimiter ? d_delimiter : '\t' ) << " ";

			int position = 0;
			size_t location;

			// escape all backslashes

			//

			string backslash(1,'\\');

			while( (location = value.find("\\", position)) != string::npos )
			{
				// location points right at the '\'

				value.insert(location,  "\\");
				position = (int) location + 2;
			}

			// escape all quotes

			//

			string quote(1,'"');
			position = 0;

			while( (location = value.find("\"", position)) != string::npos )
			{
				// location points right at the '"'

				value.insert(location,  "\\");
				position = (int) location + 2;
			}

			// escape comment characters

			// unless the comment character is a backslash or a quote, which we've already escaped....

			//

			if(d_commentchar && d_commentchar != '\\' && d_commentchar != '"')
			{
				position = 0;

				while( (location = value.find(commentchar, position)) != string::npos )
				{
					// location points right at the '"'

					value.insert(location,  "\\");
					position = (int) location + 2;
				}
			}





			// if value starts with whitespace, ends with whitespace or contains the comment character or CRLF's, quote the value, 

			//

			int size = value.size();

			if(		isspace(value[0]) || 
						isspace(value[size-1]) || 
						(value.find("\r", 0) != string::npos) || 
						(value.find("\f", 0) != string::npos) || 
						(value.find("\n", 0)!= string::npos) 
			)
			{


				value.insert(0, "\"");
				value += "\"";
			}

			// if data is deleted and there are CRLFS

			// then each line must start with a comment character.

			// The safest way is just to follow every newline character with a comment

			//

			if(		dataline.isDeleted() && ( 
						(value.find("\r", 0) != string::npos) || 
						(value.find("\f", 0) != string::npos) || 
						(value.find("\n", 0)!= string::npos) )
			  )
			{	
				position = 0;				

				while( (location = value.find("\r", position)) != string::npos )
				{
					// location points right at the '"'

					value.insert(location + 1,  commentchar);
					position = (int) location + 2;
				}
				position = 0;				
				while( (location = value.find("\f", position)) != string::npos )
				{
					// location points right at the '"'

					value.insert(location + 1,  commentchar);
					position = (int) location + 2;
				}

				position = 0;				
				while( (location = value.find("\n", position)) != string::npos )
				{
					// location points right at the '"'

					value.insert(location + 1,  commentchar);
					position = (int) location + 2;
				}
			}			

			*d_outputstream << value;

		}

		if( comment != "" && d_commentchar && d_preservecomments)
		{
			// add value's comment at end if it exists

			// and there is a comment character

			//

					*d_outputstream << "\t " << d_commentchar << comment;
		}

		// end the entry with a newline

		//

		*d_outputstream << "\n";
	}
}


}} // end namespaces




syntax highlighted by Code2HTML, v. 0.9.1