/*

cls_2: Curl Like Syntax
Yauheni A. Akhotnikau (C) 2001-2003
eao197@yahoo.com
-------------------------------------------------

Permission is granted to anyone to use this software for any purpose on any
computer system, and to redistribute it freely, subject to the following
restrictions:

1. This software 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.

2. The origin of this software must not be misrepresented, either by
   explicit claim or by omission.

3. Altered versions must be plainly marked as such, and must not be
   misrepresented as being the original software.

-------------------------------------------------

*/
/*!
	\file
	\brief Вспомогательный класс для облегчения
	преобразования значений в формат CLS.
*/

#include <assert.h>
#include <string.h>

#include <cls_2/h/to_cls_format.hpp>

namespace cls_2 {

//
// to_cls_format_t
//

static char g_special_chars[] = "{}|\\\"\n\r\t";

//! Является ли символ управляющим и нужно ли его
//! преобразовывать в шестнадцатиричное представление.
inline bool
is_spec_char( char c )
{
	return ( 0 <= c && c < ' ' );
}

// Terminal 0-char is not included
static size_t
calc_required_capacity( const char * v ) {
	assert( v );

	size_t capacity = 0;
	while( *v ) {
		if( 0 != strchr( g_special_chars, *v ) )
			++capacity;
		else if( is_spec_char( *v ) )
		{
			// Нужно будет сохранять шестнадцатиричное
			// представление символа. На это потребуются
			// дополнительные 3 символа.
			capacity += 3;
		}

		++v;
		++capacity;
	}

	return capacity;
}

static void
translate( const char * v, char * r )
{
	assert( v );
	assert( r );

	while( *v ) {
		if( 0 != strchr( g_special_chars, *v ) )
		{
			*(r++) = '\\';
			if( '\n' == *v )
				*(r++) = 'n';
			else if( '\r' == *v )
				*(r++) = 'r';
			else if( '\t' == *v )
				*(r++) = 't';
			else
				*(r++) = *v;
			++v;
		}
		else if( is_spec_char( *v ) )
		{
			static char hex_digits[] = "0123456789ABCDEF";
			(*r++) = '\\';
			(*r++) = 'x';
			(*r++) = hex_digits[
				((unsigned int)(unsigned char)*v) >> 4 ];
			(*r++) = hex_digits[
				((unsigned int)(unsigned char)*v) & 0xf ];
			++v;
		}
		else
			*(r++) = *(v++);
	}
}

char *
to_cls_format_t::format_nonspace(
	const char * v )
{
	assert( v );

	size_t required_capacity = 1 +
		calc_required_capacity( v );
	char * r = new char[ required_capacity ];
	translate( v, r );
	r[ required_capacity - 1 ] = 0;

	return r;
}

char *
to_cls_format_t::format_string(
	const char * v )
{
	assert( v );

	size_t required_capacity = 3 +
		calc_required_capacity( v );
	char * r = new char[ required_capacity ];
	r[ 0 ] = '\"';
	translate( v, r + 1 );
	r[ required_capacity - 2 ] = '\"';
	r[ required_capacity - 1 ] = 0;

	return r;
}

} /* namespace cls_2 */
