text: // 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
  
  