Index: trunk/src/cf_log.c
===================================================================
--- trunk/src/cf_log.c	(revision 11)
+++ trunk/src/cf_log.c	(revision 12)
@@ -3,12 +3,46 @@
  */
 #include "cf_log.h"
+#include "cf_file.h"
 #include "cf_thread.h"
-
+#include "cf_local.h"
+
+#include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
+#include <stdarg.h>
+#include <time.h>
 
 #ifdef _WIN32
 #else // #ifdef _WIN32
 # include <sys/stat.h>
+# include <sys/time.h>
 #endif // #ifdef _WIN32
+
+#define CHECK_INVALID_CTX(__ctx)				\
+	if (__ctx == NULL)							\
+		return CF_ERROR_LOG_INVALID_CTX
+
+#define LOCK_LOG_CTX(__ctx)						\
+	if (CF_Mutex_Lock (&__ctx->mutex) < 0)		\
+		return CF_ERROR_LOG_LOCK_CTX
+
+#define UNLOCK_LOG_CTX(__ctx)					\
+	if (CF_Mutex_Unlock (&__ctx->mutex) < 0)	\
+		return CF_ERROR_LOG_UNLOCK_CTX
+
+#define CF_LOG_BUFFER_DEFAULT_SIZE		128 * 1024
+
+typedef struct __cf_util_datetime__
+{
+	int year;
+	int month;
+	int day;
+	int week; /* SUN:0 ~ SAT:6 */
+
+	int hour;
+	int min;
+	int sec;
+	int usec;
+} S_CF_Log_DateTime, CF_Log_DateTime;
 
 typedef struct __cf_log_ctx__ {
@@ -16,6 +50,6 @@
 	int			fd;
 	char		* buffer;
-	int			entireLength;
-	int			bufferLength;
+	size_t		size;	/* entire size of buffer */
+	size_t		length; /* data length in current */
 	CF_Mutex	mutex;
 } S_CF_LOG_CTX, CF_LOG_CTX;
@@ -23,19 +57,142 @@
 typedef struct __cf_log_environment__ {
 	__blksize_t	fsBlockSize;
-} S_CF_Log_Environment, CF_Log_Environment;
-
-CF_Log_Environment	gLogEnvironment;
-
-int
-CF_Log_Initialize (void)
+	CF_Log_Ctx	* ctxPool;
+	int			ctxSize;
+} S_CF_LOG_ENVIRONMENT, CF_LOG_ENVIRONMENT;
+
+CF_LOG_ENVIRONMENT	gLogEnvironment;
+
+#if defined(_WIN32) || defined(_WIN64)
+/* #if defined(_WIN32) || defined(_WIN64) {{{ */
+struct timezone
+{
+	int tz_minuteswest; /* minutes W of Greenwich */
+	int tz_dsttime;     /* type of dst correction */
+};
+
+// Definition of a gettimeofday function
+int gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+	// Define a structure to receive the current Windows filetime
+	FILETIME ft;
+
+	// Initialize the present time to 0 and the timezone to UTC
+	unsigned __int64 ui64 =0;
+	static int tzflag = 0;
+
+	if (NULL != tv)
+	{
+		GetSystemTimeAsFileTime(&ft);
+
+		ui64 = (((unsigned __int64) ft.dwHighDateTime << 32)
+				+ (unsigned __int64) ft.dwLowDateTime);
+
+		if (ui64)
+		{
+			ui64 /= 10;
+			ui64 -= ((369 * 365 + 89) * (unsigned __int64) 86400) * 1000000;
+		}
+
+		// Finally change microseconds to seconds and place in the seconds value.
+		// The modulus picks up the microseconds.
+		tv->tv_sec = (long)(ui64 / 1000000UL);
+		tv->tv_usec = (long)(ui64 % 1000000UL);
+	}
+
+	if (NULL != tz)
+	{
+		if (!tzflag)
+		{
+			_tzset();
+			tzflag++;
+		}
+
+		// Adjust for the timezone west of Greenwich
+		tz->tz_minuteswest = _timezone / 60;
+		tz->tz_dsttime = _daylight;
+	}
+
+	return 0;
+}
+#endif // #if defined(_WIN32) || defined(_WIN64)
+/* }}} #if defined(_WIN32) || defined(_WIN64) */
+
+int
+CF_Log_Local_GetTime (CF_Log_DateTime * dt)
+{
+	struct timeval	timeVal;
+	struct tm		* timeSt;
+
+	gettimeofday (&timeVal, NULL);
+	timeSt = localtime (&timeVal.tv_sec);
+
+	dt->year	= timeSt->tm_year + 1900;
+	dt->month	= timeSt->tm_mon + 1;
+	dt->day		= timeSt->tm_mday;
+	dt->week	= timeSt->tm_wday;
+
+	dt->hour	= timeSt->tm_hour;
+	dt->min		= timeSt->tm_min;
+	dt->sec		= timeSt->tm_sec;
+
+	dt->usec	= (int) timeVal.tv_usec;
+
+	return CF_OK;
+}
+
+int
+CF_Log_Local_GetTimeString (char * buffer)
+{
+	CF_Log_DateTime dt;
+	CF_Log_Local_GetTime (&dt);
+
+	sprintf (buffer, "%02d-%02d-%02d %02d:%02d:%02d.%03d",
+					 dt.year, dt.month, dt.day, 
+					 dt.hour, dt.min, dt.sec, dt.usec);
+
+	return CF_OK;
+}
+
+int
+CF_Log_Local_Push (CF_LOG_CTX	* ctx,
+				   const char	* buffer)
+{
+	strncat (ctx->buffer + ctx->length,
+			 buffer,
+			 ctx->size - ctx->length);
+	ctx->length = strlen (ctx->buffer);
+
+	return CF_OK;
+}
+
+int
+CF_Log_Local_Flush (CF_LOG_CTX * ctx)
+{
+	if (CF_File_Write (ctx->fd, ctx->buffer, ctx->length) < 0)
+		return CF_ERROR_LOG_FLUSH;
+
+	memset (ctx->buffer, 0x00, ctx->size);
+	ctx->length = 0;
+
+	return CF_OK;
+}
+
+int
+CF_Log_Initialize (const int logPool)
 {
 	struct stat fsstat;
 
-	memset (&gLogEnvironment, 0x00, sizeof (CF_Log_Environment));
-
-	if (stat ("./", &fsstat) < 0)
+	memset (&gLogEnvironment, 0x00, sizeof (CF_LOG_ENVIRONMENT));
+
+	if (stat (".", &fsstat) < 0)
 		return CF_ERROR_LOG_INITIALIZE;
 
 	gLogEnvironment.fsBlockSize = fsstat.st_blksize;
+	if (logPool > 0)
+	{
+		gLogEnvironment.ctxPool =
+			(CF_Log_Ctx *) calloc ((size_t) logPool, sizeof (CF_Log_Ctx));
+		gLogEnvironment.ctxSize = logPool;
+	}
 
 	return CF_OK;
@@ -45,6 +202,175 @@
 CF_Log_Finalize (void)
 {
-	memset (&gLogEnvironment, 0x00, sizeof (CF_Log_Environment));
-
-	return CF_OK;
-}
+	memset (&gLogEnvironment, 0x00, sizeof (CF_LOG_ENVIRONMENT));
+
+	return CF_OK;
+}
+
+CF_Log_Ctx
+CF_Log_CreateCtx (const char	* path,
+				  const int		memsize)
+{
+	int result = 0;
+	int size = (memsize == CF_LOG_BUFFER_DEFAULT)
+			 ? CF_LOG_BUFFER_DEFAULT_SIZE
+			 : memsize;
+	CF_LOG_CTX	* context = NULL;
+
+	if (path == NULL)
+		return NULL;
+
+	TRY
+	{
+		context = (CF_LOG_CTX *) calloc (sizeof (CF_LOG_CTX), 1);
+		if (context == NULL)
+		{
+			result = -1;
+			TRY_BREAK;
+		}
+
+		context->fd = CF_File_Create (path);
+		if (context->fd < 0)
+		{
+			result = -2;
+			TRY_BREAK;
+		}
+		sprintf (context->path, "%s", path);
+
+		if (size > 0)
+		{
+			context->buffer = (char *) calloc ((size_t) size + 1, 1);
+			if (context->buffer == NULL)
+			{
+				result = -3;
+				TRY_BREAK;
+			}
+			context->size = (size_t) size;
+		}
+	}
+	CATCH_IF (result < 0)
+	{
+		CF_Log_DestroyCtx ((CF_Log_Ctx) context);
+		return NULL;
+	}
+
+	return (CF_Log_Ctx) context;
+}
+
+int
+CF_Log_SetMultiThread (CF_Log_Ctx ctx)
+{
+	CF_LOG_CTX * context = (CF_LOG_CTX *) ctx;
+
+	CHECK_INVALID_CTX (ctx);
+
+	if (CF_Mutex_Create (&context->mutex) < 0)
+		return CF_ERROR_LOG_SET_MULTITHREAD;
+
+	return CF_OK;
+}
+
+int
+CF_Log_UnsetMultiThread (CF_Log_Ctx ctx)
+{
+	CF_LOG_CTX * context = (CF_LOG_CTX *) ctx;
+
+	CHECK_INVALID_CTX (ctx);
+
+	if (CF_Mutex_Destory (&context->mutex) < 0)
+		return CF_ERROR_LOG_UNSET_MULTITHREAD;
+
+	return CF_OK;
+}
+
+int
+CF_Log_DestroyCtx (CF_Log_Ctx ctx)
+{
+	CF_LOG_CTX * context = (CF_LOG_CTX *) ctx;
+
+	CHECK_INVALID_CTX (ctx);
+
+	memset (context->path, 0x00, sizeof (context->path));
+
+	if (context->buffer != NULL)
+	{
+		/* FIXME : write residual data in buffer */
+
+		free (context->buffer);
+		context->buffer = NULL;
+		context->size = 0;
+	}
+
+	CF_File_Close (context->fd);
+
+	if (context->mutex != NULL)
+	{
+		if (CF_Mutex_Destory (&context->mutex) < 0)
+			/* do something ? */;
+
+		context->mutex = NULL;
+	}
+
+	return CF_OK;
+}
+
+int
+CF_Log_Write (CF_Log_Ctx	ctx,
+			  const char	* prefix,
+			  const char	* fmt, ...)
+{
+	CF_LOG_CTX	* context = (CF_LOG_CTX *) ctx;
+	va_list		valist;
+	char		buffer[4096] = {0x00,};
+	size_t		length = 0;
+
+	CHECK_INVALID_CTX (ctx);
+
+	LOCK_LOG_CTX (context);
+	va_start (valist, fmt);
+
+	strncat (buffer, "[", 1);
+	CF_Log_Local_GetTimeString (buffer + strlen (buffer));
+	sprintf (buffer + strlen (buffer), "][%s] ", prefix);
+	vsprintf (buffer + strlen (buffer), fmt, valist);
+
+	if (context->size == CF_LOG_BUFFER_NO)
+	{
+		context->buffer = buffer;
+		context->length = strlen (buffer);
+
+		CF_Log_Local_Flush (context);
+
+		context->buffer = NULL;
+		/* context->length = 0; // already did this in flush */
+	}
+	else /* (context->size > 0) */
+	{
+		length = context->size - context->length;
+		CF_Log_Local_Push (context, buffer);
+
+		if (context->length == context->size)
+		{
+			CF_Log_Local_Flush (context);
+			CF_Log_Local_Push (context, buffer + length);
+		}
+	}
+
+	va_end (valist);
+	UNLOCK_LOG_CTX (context);
+
+	return CF_OK;
+}
+
+int
+CF_Log_Flush (CF_Log_Ctx ctx)
+{
+	CF_LOG_CTX * context = (CF_LOG_CTX *) ctx;
+
+	CHECK_INVALID_CTX (ctx);
+
+	LOCK_LOG_CTX (context);
+	CF_Log_Local_Flush (context);
+	UNLOCK_LOG_CTX (context);
+
+	return CF_OK;
+}
