/*
 *  ADP (Another Data Processor) www.adp.la
 *  Copyright (C) 2010 Katsuhisa Ohfuji <katsuhisa@ohfuji.name>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 2 as
 *  published by the Free Software Foundation.
 *
 *  This program 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 this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 *  MA 02110-1301, USA.
 */
#ifndef KZ_C_FORMAT
#define KZ_C_FORMAT
#include <string.h>
#include <stdarg.h>

#ifdef _WIN32
#define vsnprintf	_vsnprintf
#endif

inline std::string cformat( const char *format, ...)
{
	int	bufsize = 10240;	// 適当なサイズ
	std::vector<char>	buff(bufsize);
	va_list args;

	// 適当なバッファサイズで先ずは、vsnprintfを試す。
	// 出力がバッファサイズ以上の場合、VC++ .NET 2003の場合は -1、
	// glibc2.1以降は、書き込みに必要なサイズを返す。
	va_start(args, format);
	int vssize = vsnprintf( &buff[0], bufsize, format, args);
	va_end(args);

	// vsnprintfが成功した場合終了する。
	if ( vssize >= 0 && vssize < bufsize ) {
		buff.resize(vssize);
		return std::string( buff.begin(), buff.end() );
	}

#ifdef _WIN32
	// VC++ .NET 2003 書き込みに必要なサイズを取得する。
	va_start(args, format);
	vssize = _vscprintf( format, args); 
	va_end(args);
#endif
	
	if ( vssize < 0 ) throw std::runtime_error(format);

	// サイズを再割り当てし、再度試す
	buff.resize(vssize + 1);
	va_start(args, format);
	vssize = vsnprintf( &buff[0], vssize + 1, format, args);
	va_end(args);
	if ( vssize < 0 ) throw std::runtime_error(format);
	buff.resize(vssize);
	return std::string( buff.begin(), buff.end() );
}

inline void cformat_cat( std::string &out, const char *format, ...)
{
	int	bufsize = 10240;	// 適当なサイズ
	std::vector<char>	buff(bufsize);
	va_list args;

	// 適当なバッファサイズで先ずは、vsnprintfを試す。
	// 出力がバッファサイズ以上の場合、VC++ .NET 2003の場合は -1、
	// glibc2.1以降は、書き込みに必要なサイズを返す。
	va_start(args, format);
	int vssize = vsnprintf( &buff[0], bufsize, format, args);
	va_end(args);

	// vsnprintfが成功した場合終了する。
	if ( vssize >= 0 && vssize < bufsize ) {
		buff.resize(vssize);
		out.insert( out.end(), buff.begin(), buff.end());
		return;
	}

#ifdef _WIN32
	// VC++ .NET 2003 書き込みに必要なサイズを取得する。
	va_start(args, format);
	vssize = _vscprintf( format, args); 
	va_end(args);
#endif
	
	if ( vssize < 0 ) throw std::runtime_error(format);

	// サイズを再割り当てし、再度試す
	buff.resize(vssize + 1);
	va_start(args, format);
	vssize = vsnprintf( &buff[0], vssize + 1, format, args);
	va_end(args);
	if ( vssize < 0 ) throw std::runtime_error(format);
	buff.resize(vssize);
	out.insert( out.end(), buff.begin(), buff.end());
}


#endif
