Blame winpr/libwinpr/utils/wlog/wlog.c

Packit 1fb8d4
/**
Packit 1fb8d4
 * WinPR: Windows Portable Runtime
Packit 1fb8d4
 * WinPR Logger
Packit 1fb8d4
 *
Packit 1fb8d4
 * Copyright 2013 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit 1fb8d4
 *
Packit 1fb8d4
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit 1fb8d4
 * you may not use this file except in compliance with the License.
Packit 1fb8d4
 * You may obtain a copy of the License at
Packit 1fb8d4
 *
Packit 1fb8d4
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit 1fb8d4
 *
Packit 1fb8d4
 * Unless required by applicable law or agreed to in writing, software
Packit 1fb8d4
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit 1fb8d4
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit 1fb8d4
 * See the License for the specific language governing permissions and
Packit 1fb8d4
 * limitations under the License.
Packit 1fb8d4
 */
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_CONFIG_H
Packit 1fb8d4
#include "config.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include <stdio.h>
Packit 1fb8d4
#include <string.h>
Packit 1fb8d4
Packit 1fb8d4
#include <winpr/crt.h>
Packit 1fb8d4
#include <winpr/print.h>
Packit 1fb8d4
#include <winpr/debug.h>
Packit 1fb8d4
#include <winpr/environment.h>
Packit 1fb8d4
#include <winpr/wlog.h>
Packit 1fb8d4
Packit 1fb8d4
#if defined(ANDROID)
Packit 1fb8d4
#include <android/log.h>
Packit 1fb8d4
#include "../log.h"
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
#include "wlog.h"
Packit 1fb8d4
Packit 1fb8d4
struct _wLogFilter
Packit 1fb8d4
{
Packit 1fb8d4
	DWORD Level;
Packit 1fb8d4
	LPSTR* Names;
Packit 1fb8d4
	DWORD NameCount;
Packit 1fb8d4
};
Packit 1fb8d4
typedef struct _wLogFilter wLogFilter;
Packit 1fb8d4
Packit Service 5a9772
#define WLOG_FILTER_NOT_FILTERED -1
Packit Service 5a9772
#define WLOG_FILTER_NOT_INITIALIZED -2
Packit 1fb8d4
/**
Packit 1fb8d4
 * References for general logging concepts:
Packit 1fb8d4
 *
Packit 1fb8d4
 * Short introduction to log4j:
Packit 1fb8d4
 * http://logging.apache.org/log4j/1.2/manual.html
Packit 1fb8d4
 *
Packit 1fb8d4
 * logging - Logging facility for Python:
Packit 1fb8d4
 * http://docs.python.org/2/library/logging.html
Packit 1fb8d4
 */
Packit 1fb8d4
Packit Service 5a9772
LPCSTR WLOG_LEVELS[7] = { "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL", "OFF" };
Packit 1fb8d4
Packit 1fb8d4
static INIT_ONCE _WLogInitialized = INIT_ONCE_STATIC_INIT;
Packit 1fb8d4
static DWORD g_FilterCount = 0;
Packit 1fb8d4
static wLogFilter* g_Filters = NULL;
Packit 1fb8d4
static wLog* g_RootLog = NULL;
Packit 1fb8d4
Packit 1fb8d4
static wLog* WLog_New(LPCSTR name, wLog* rootLogger);
Packit 1fb8d4
static void WLog_Free(wLog* log);
Packit 1fb8d4
static LONG WLog_GetFilterLogLevel(wLog* log);
Packit 1fb8d4
static int WLog_ParseLogLevel(LPCSTR level);
Packit 1fb8d4
static BOOL WLog_ParseFilter(wLogFilter* filter, LPCSTR name);
Packit 1fb8d4
static BOOL WLog_ParseFilters(void);
Packit 1fb8d4
Packit 1fb8d4
#if !defined(_WIN32)
Packit 1fb8d4
static void WLog_Uninit_(void) __attribute__((destructor));
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
static void WLog_Uninit_(void)
Packit 1fb8d4
{
Packit 1fb8d4
	DWORD index;
Packit 1fb8d4
	wLog* child = NULL;
Packit 1fb8d4
	wLog* root = g_RootLog;
Packit 1fb8d4
Packit 1fb8d4
	if (!root)
Packit 1fb8d4
		return;
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < root->ChildrenCount; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		child = root->Children[index];
Packit 1fb8d4
		WLog_Free(child);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	WLog_Free(root);
Packit 1fb8d4
	g_RootLog = NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL CALLBACK WLog_InitializeRoot(PINIT_ONCE InitOnce, PVOID Parameter, PVOID* Context)
Packit 1fb8d4
{
Packit 1fb8d4
	char* env;
Packit 1fb8d4
	DWORD nSize;
Packit 1fb8d4
	DWORD logAppenderType;
Packit 1fb8d4
	LPCSTR appender = "WLOG_APPENDER";
Packit 1fb8d4
Packit 1fb8d4
	if (!(g_RootLog = WLog_New("", NULL)))
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	g_RootLog->IsRoot = TRUE;
Packit 1fb8d4
	WLog_ParseFilters();
Packit 1fb8d4
	logAppenderType = WLOG_APPENDER_CONSOLE;
Packit 1fb8d4
	nSize = GetEnvironmentVariableA(appender, NULL, 0);
Packit 1fb8d4
Packit 1fb8d4
	if (nSize)
Packit 1fb8d4
	{
Packit Service 5a9772
		env = (LPSTR)malloc(nSize);
Packit 1fb8d4
Packit 1fb8d4
		if (!env)
Packit 1fb8d4
			goto fail;
Packit 1fb8d4
Packit 1fb8d4
		if (GetEnvironmentVariableA(appender, env, nSize) != nSize - 1)
Packit 1fb8d4
		{
Packit 1fb8d4
			fprintf(stderr, "%s environment variable modified in my back", appender);
Packit 1fb8d4
			free(env);
Packit 1fb8d4
			goto fail;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (_stricmp(env, "CONSOLE") == 0)
Packit 1fb8d4
			logAppenderType = WLOG_APPENDER_CONSOLE;
Packit 1fb8d4
		else if (_stricmp(env, "FILE") == 0)
Packit 1fb8d4
			logAppenderType = WLOG_APPENDER_FILE;
Packit 1fb8d4
		else if (_stricmp(env, "BINARY") == 0)
Packit 1fb8d4
			logAppenderType = WLOG_APPENDER_BINARY;
Packit 1fb8d4
Packit 1fb8d4
#ifdef HAVE_SYSLOG_H
Packit 1fb8d4
		else if (_stricmp(env, "SYSLOG") == 0)
Packit 1fb8d4
			logAppenderType = WLOG_APPENDER_SYSLOG;
Packit 1fb8d4
Packit 1fb8d4
#endif /* HAVE_SYSLOG_H */
Packit 1fb8d4
#ifdef HAVE_JOURNALD_H
Packit 1fb8d4
		else if (_stricmp(env, "JOURNALD") == 0)
Packit 1fb8d4
			logAppenderType = WLOG_APPENDER_JOURNALD;
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
		else if (_stricmp(env, "UDP") == 0)
Packit 1fb8d4
			logAppenderType = WLOG_APPENDER_UDP;
Packit 1fb8d4
Packit 1fb8d4
		free(env);
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!WLog_SetLogAppenderType(g_RootLog, logAppenderType))
Packit 1fb8d4
		goto fail;
Packit 1fb8d4
Packit 1fb8d4
#if defined(_WIN32)
Packit 1fb8d4
	atexit(WLog_Uninit_);
Packit 1fb8d4
#endif
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
fail:
Packit 1fb8d4
	free(g_RootLog);
Packit 1fb8d4
	g_RootLog = NULL;
Packit 1fb8d4
	return FALSE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL log_recursion(LPCSTR file, LPCSTR fkt, int line)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL status = FALSE;
Packit 1fb8d4
	char** msg = NULL;
Packit 1fb8d4
	size_t used, i;
Packit 1fb8d4
	void* bt = winpr_backtrace(20);
Packit 1fb8d4
#if defined(ANDROID)
Packit 1fb8d4
	LPCSTR tag = WINPR_TAG("utils.wlog");
Packit 1fb8d4
#endif
Packit 1fb8d4
Packit 1fb8d4
	if (!bt)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	msg = winpr_backtrace_symbols(bt, &used);
Packit 1fb8d4
Packit 1fb8d4
	if (!msg)
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
#if defined(ANDROID)
Packit 1fb8d4
Packit 1fb8d4
	if (__android_log_print(ANDROID_LOG_FATAL, tag, "Recursion detected!!!") < 0)
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit Service 5a9772
	if (__android_log_print(ANDROID_LOG_FATAL, tag, "Check %s [%s:%d]", fkt, file, line) < 0)
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < used; i++)
Packit 1fb8d4
		if (__android_log_print(ANDROID_LOG_FATAL, tag, "%zd: %s", i, msg[i]) < 0)
Packit 1fb8d4
			goto out;
Packit 1fb8d4
Packit 1fb8d4
#else
Packit 1fb8d4
Packit 1fb8d4
	if (fprintf(stderr, "[%s]: Recursion detected!\n", fkt) < 0)
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	if (fprintf(stderr, "[%s]: Check %s:%d\n", fkt, file, line) < 0)
Packit 1fb8d4
		goto out;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < used; i++)
Packit Service 5a9772
		if (fprintf(stderr, "%s: %" PRIuz ": %s\n", fkt, i, msg[i]) < 0)
Packit 1fb8d4
			goto out;
Packit 1fb8d4
Packit 1fb8d4
#endif
Packit 1fb8d4
	status = TRUE;
Packit 1fb8d4
out:
Packit 1fb8d4
	free(msg);
Packit 1fb8d4
	winpr_backtrace_free(bt);
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL WLog_Write(wLog* log, wLogMessage* message)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL status;
Packit 1fb8d4
	wLogAppender* appender;
Packit 1fb8d4
	appender = WLog_GetLogAppender(log);
Packit 1fb8d4
Packit 1fb8d4
	if (!appender)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!appender->active)
Packit 1fb8d4
		if (!WLog_OpenAppender(log))
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!appender->WriteMessage)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	EnterCriticalSection(&appender->lock);
Packit 1fb8d4
Packit 1fb8d4
	if (appender->recursive)
Packit Service 5a9772
		status = log_recursion(message->FileName, message->FunctionName, message->LineNumber);
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		appender->recursive = TRUE;
Packit 1fb8d4
		status = appender->WriteMessage(log, appender, message);
Packit 1fb8d4
		appender->recursive = FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	LeaveCriticalSection(&appender->lock);
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL WLog_WriteData(wLog* log, wLogMessage* message)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL status;
Packit 1fb8d4
	wLogAppender* appender;
Packit 1fb8d4
	appender = WLog_GetLogAppender(log);
Packit 1fb8d4
Packit 1fb8d4
	if (!appender)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!appender->active)
Packit 1fb8d4
		if (!WLog_OpenAppender(log))
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!appender->WriteDataMessage)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	EnterCriticalSection(&appender->lock);
Packit 1fb8d4
Packit 1fb8d4
	if (appender->recursive)
Packit Service 5a9772
		status = log_recursion(message->FileName, message->FunctionName, message->LineNumber);
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		appender->recursive = TRUE;
Packit 1fb8d4
		status = appender->WriteDataMessage(log, appender, message);
Packit 1fb8d4
		appender->recursive = FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	LeaveCriticalSection(&appender->lock);
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL WLog_WriteImage(wLog* log, wLogMessage* message)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL status;
Packit 1fb8d4
	wLogAppender* appender;
Packit 1fb8d4
	appender = WLog_GetLogAppender(log);
Packit 1fb8d4
Packit 1fb8d4
	if (!appender)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!appender->active)
Packit 1fb8d4
		if (!WLog_OpenAppender(log))
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!appender->WriteImageMessage)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	EnterCriticalSection(&appender->lock);
Packit 1fb8d4
Packit 1fb8d4
	if (appender->recursive)
Packit Service 5a9772
		status = log_recursion(message->FileName, message->FunctionName, message->LineNumber);
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		appender->recursive = TRUE;
Packit 1fb8d4
		status = appender->WriteImageMessage(log, appender, message);
Packit 1fb8d4
		appender->recursive = FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	LeaveCriticalSection(&appender->lock);
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL WLog_WritePacket(wLog* log, wLogMessage* message)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL status;
Packit 1fb8d4
	wLogAppender* appender;
Packit 1fb8d4
	appender = WLog_GetLogAppender(log);
Packit 1fb8d4
Packit 1fb8d4
	if (!appender)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!appender->active)
Packit 1fb8d4
		if (!WLog_OpenAppender(log))
Packit 1fb8d4
			return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (!appender->WritePacketMessage)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	EnterCriticalSection(&appender->lock);
Packit 1fb8d4
Packit 1fb8d4
	if (appender->recursive)
Packit Service 5a9772
		status = log_recursion(message->FileName, message->FunctionName, message->LineNumber);
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		appender->recursive = TRUE;
Packit 1fb8d4
		status = appender->WritePacketMessage(log, appender, message);
Packit 1fb8d4
		appender->recursive = FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	LeaveCriticalSection(&appender->lock);
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
BOOL WLog_PrintMessageVA(wLog* log, DWORD type, DWORD level, DWORD line, const char* file,
Packit Service 5a9772
                         const char* function, va_list args)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL status = FALSE;
Packit 1fb8d4
	wLogMessage message = { 0 };
Packit Service 5a9772
	message.Type = type;
Packit 1fb8d4
	message.Level = level;
Packit 1fb8d4
	message.LineNumber = line;
Packit 1fb8d4
	message.FileName = file;
Packit 1fb8d4
	message.FunctionName = function;
Packit 1fb8d4
Packit 1fb8d4
	switch (type)
Packit 1fb8d4
	{
Packit 1fb8d4
		case WLOG_MESSAGE_TEXT:
Packit 1fb8d4
			message.FormatString = va_arg(args, const char*);
Packit 1fb8d4
Packit 1fb8d4
			if (!strchr(message.FormatString, '%'))
Packit 1fb8d4
			{
Packit Service 5a9772
				message.TextString = (LPSTR)message.FormatString;
Packit 1fb8d4
				status = WLog_Write(log, &message);
Packit 1fb8d4
			}
Packit 1fb8d4
			else
Packit 1fb8d4
			{
Packit 1fb8d4
				char formattedLogMessage[WLOG_MAX_STRING_SIZE];
Packit 1fb8d4
Packit Service 5a9772
				if (wvsnprintfx(formattedLogMessage, WLOG_MAX_STRING_SIZE - 1, message.FormatString,
Packit Service 5a9772
				                args) < 0)
Packit 1fb8d4
					return FALSE;
Packit 1fb8d4
Packit 1fb8d4
				message.TextString = formattedLogMessage;
Packit 1fb8d4
				status = WLog_Write(log, &message);
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case WLOG_MESSAGE_DATA:
Packit 1fb8d4
			message.Data = va_arg(args, void*);
Packit 1fb8d4
			message.Length = va_arg(args, int);
Packit 1fb8d4
			status = WLog_WriteData(log, &message);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case WLOG_MESSAGE_IMAGE:
Packit 1fb8d4
			message.ImageData = va_arg(args, void*);
Packit 1fb8d4
			message.ImageWidth = va_arg(args, int);
Packit 1fb8d4
			message.ImageHeight = va_arg(args, int);
Packit 1fb8d4
			message.ImageBpp = va_arg(args, int);
Packit 1fb8d4
			status = WLog_WriteImage(log, &message);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		case WLOG_MESSAGE_PACKET:
Packit 1fb8d4
			message.PacketData = va_arg(args, void*);
Packit 1fb8d4
			message.PacketLength = va_arg(args, int);
Packit 1fb8d4
			message.PacketFlags = va_arg(args, int);
Packit 1fb8d4
			status = WLog_WritePacket(log, &message);
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		default:
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
BOOL WLog_PrintMessage(wLog* log, DWORD type, DWORD level, DWORD line, const char* file,
Packit Service 5a9772
                       const char* function, ...)
Packit 1fb8d4
{
Packit 1fb8d4
	BOOL status;
Packit 1fb8d4
	va_list args;
Packit 1fb8d4
	va_start(args, function);
Packit 1fb8d4
	status = WLog_PrintMessageVA(log, type, level, line, file, function, args);
Packit 1fb8d4
	va_end(args);
Packit 1fb8d4
	return status;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
DWORD WLog_GetLogLevel(wLog* log)
Packit 1fb8d4
{
Packit Service 5a9772
	if (!log)
Packit Service 5a9772
		return WLOG_OFF;
Packit Service 5a9772
Packit Service 5a9772
	if (log->FilterLevel <= WLOG_FILTER_NOT_INITIALIZED)
Packit 1fb8d4
		log->FilterLevel = WLog_GetFilterLogLevel(log);
Packit 1fb8d4
Packit Service 5a9772
	if (log->FilterLevel > WLOG_FILTER_NOT_FILTERED)
Packit Service 5a9772
		return (DWORD)log->FilterLevel;
Packit 1fb8d4
	else if (log->Level == WLOG_LEVEL_INHERIT)
Packit 1fb8d4
		log->Level = WLog_GetLogLevel(log->Parent);
Packit 1fb8d4
Packit 1fb8d4
	return log->Level;
Packit 1fb8d4
}
Packit 1fb8d4
Packit Service 5a9772
BOOL WLog_IsLevelActive(wLog* _log, DWORD _log_level)
Packit Service 5a9772
{
Packit Service 5a9772
	DWORD level;
Packit Service 5a9772
Packit Service 5a9772
	if (!_log)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	level = WLog_GetLogLevel(_log);
Packit Service 5a9772
Packit Service 5a9772
	if (level == WLOG_OFF)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	return _log_level >= level;
Packit Service 5a9772
}
Packit Service 5a9772
Packit 1fb8d4
BOOL WLog_SetStringLogLevel(wLog* log, LPCSTR level)
Packit 1fb8d4
{
Packit 1fb8d4
	int lvl;
Packit 1fb8d4
Packit 1fb8d4
	if (!log || !level)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	lvl = WLog_ParseLogLevel(level);
Packit 1fb8d4
Packit 1fb8d4
	if (lvl < 0)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	return WLog_SetLogLevel(log, (DWORD)lvl);
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static BOOL WLog_reset_log_filters(wLog* log)
Packit Service 5a9772
{
Packit Service 5a9772
	DWORD x;
Packit Service 5a9772
Packit Service 5a9772
	if (!log)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	log->FilterLevel = WLOG_FILTER_NOT_INITIALIZED;
Packit Service 5a9772
Packit Service 5a9772
	for (x = 0; x < log->ChildrenCount; x++)
Packit Service 5a9772
	{
Packit Service 5a9772
		wLog* child = log->Children[x];
Packit Service 5a9772
Packit Service 5a9772
		if (!WLog_reset_log_filters(child))
Packit Service 5a9772
			return FALSE;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL WLog_AddStringLogFilters(LPCSTR filter)
Packit 1fb8d4
{
Packit 1fb8d4
	DWORD pos;
Packit 1fb8d4
	DWORD size;
Packit 1fb8d4
	DWORD count;
Packit 1fb8d4
	LPSTR p;
Packit 1fb8d4
	LPSTR filterStr;
Packit 1fb8d4
	LPSTR cp;
Packit 1fb8d4
	wLogFilter* tmp;
Packit 1fb8d4
Packit 1fb8d4
	if (!filter)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	count = 1;
Packit 1fb8d4
	p = (LPSTR)filter;
Packit 1fb8d4
Packit 1fb8d4
	while ((p = strchr(p, ',')) != NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		count++;
Packit 1fb8d4
		p++;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	pos = g_FilterCount;
Packit 1fb8d4
	size = g_FilterCount + count;
Packit Service 5a9772
	tmp = (wLogFilter*)realloc(g_Filters, size * sizeof(wLogFilter));
Packit 1fb8d4
Packit 1fb8d4
	if (!tmp)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	g_Filters = tmp;
Packit 1fb8d4
	cp = (LPSTR)_strdup(filter);
Packit 1fb8d4
Packit 1fb8d4
	if (!cp)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	p = cp;
Packit 1fb8d4
	filterStr = cp;
Packit 1fb8d4
Packit 1fb8d4
	do
Packit 1fb8d4
	{
Packit 1fb8d4
		p = strchr(p, ',');
Packit 1fb8d4
Packit 1fb8d4
		if (p)
Packit 1fb8d4
			*p = '\0';
Packit 1fb8d4
Packit 1fb8d4
		if (pos < size)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (!WLog_ParseFilter(&g_Filters[pos++], filterStr))
Packit 1fb8d4
			{
Packit 1fb8d4
				free(cp);
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
			break;
Packit 1fb8d4
Packit 1fb8d4
		if (p)
Packit 1fb8d4
		{
Packit 1fb8d4
			filterStr = p + 1;
Packit 1fb8d4
			p++;
Packit 1fb8d4
		}
Packit Service 5a9772
	} while (p != NULL);
Packit 1fb8d4
Packit 1fb8d4
	g_FilterCount = size;
Packit 1fb8d4
	free(cp);
Packit Service 5a9772
	return WLog_reset_log_filters(WLog_GetRoot());
Packit Service 5a9772
}
Packit Service 5a9772
Packit Service 5a9772
static BOOL WLog_UpdateInheritLevel(wLog* log, DWORD logLevel)
Packit Service 5a9772
{
Packit Service 5a9772
	if (!log)
Packit Service 5a9772
		return FALSE;
Packit Service 5a9772
Packit Service 5a9772
	if (log->inherit)
Packit Service 5a9772
	{
Packit Service 5a9772
		DWORD x;
Packit Service 5a9772
		log->Level = logLevel;
Packit Service 5a9772
Packit Service 5a9772
		for (x = 0; x < log->ChildrenCount; x++)
Packit Service 5a9772
		{
Packit Service 5a9772
			wLog* child = log->Children[x];
Packit Service 5a9772
Packit Service 5a9772
			if (!WLog_UpdateInheritLevel(child, logLevel))
Packit Service 5a9772
				return FALSE;
Packit Service 5a9772
		}
Packit Service 5a9772
	}
Packit Service 5a9772
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL WLog_SetLogLevel(wLog* log, DWORD logLevel)
Packit 1fb8d4
{
Packit Service 5a9772
	DWORD x;
Packit Service 5a9772
Packit 1fb8d4
	if (!log)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if ((logLevel > WLOG_OFF) && (logLevel != WLOG_LEVEL_INHERIT))
Packit 1fb8d4
		logLevel = WLOG_OFF;
Packit 1fb8d4
Packit 1fb8d4
	log->Level = logLevel;
Packit Service 5a9772
	log->inherit = (logLevel == WLOG_LEVEL_INHERIT) ? TRUE : FALSE;
Packit Service 5a9772
Packit Service 5a9772
	for (x = 0; x < log->ChildrenCount; x++)
Packit Service 5a9772
	{
Packit Service 5a9772
		wLog* child = log->Children[x];
Packit Service 5a9772
Packit Service 5a9772
		if (!WLog_UpdateInheritLevel(child, logLevel))
Packit Service 5a9772
			return FALSE;
Packit Service 5a9772
	}
Packit Service 5a9772
Packit Service 5a9772
	return WLog_reset_log_filters(log);
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
int WLog_ParseLogLevel(LPCSTR level)
Packit 1fb8d4
{
Packit 1fb8d4
	int iLevel = -1;
Packit 1fb8d4
Packit 1fb8d4
	if (!level)
Packit 1fb8d4
		return -1;
Packit 1fb8d4
Packit 1fb8d4
	if (_stricmp(level, "TRACE") == 0)
Packit 1fb8d4
		iLevel = WLOG_TRACE;
Packit 1fb8d4
	else if (_stricmp(level, "DEBUG") == 0)
Packit 1fb8d4
		iLevel = WLOG_DEBUG;
Packit 1fb8d4
	else if (_stricmp(level, "INFO") == 0)
Packit 1fb8d4
		iLevel = WLOG_INFO;
Packit 1fb8d4
	else if (_stricmp(level, "WARN") == 0)
Packit 1fb8d4
		iLevel = WLOG_WARN;
Packit 1fb8d4
	else if (_stricmp(level, "ERROR") == 0)
Packit 1fb8d4
		iLevel = WLOG_ERROR;
Packit 1fb8d4
	else if (_stricmp(level, "FATAL") == 0)
Packit 1fb8d4
		iLevel = WLOG_FATAL;
Packit 1fb8d4
	else if (_stricmp(level, "OFF") == 0)
Packit 1fb8d4
		iLevel = WLOG_OFF;
Packit 1fb8d4
Packit 1fb8d4
	return iLevel;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL WLog_ParseFilter(wLogFilter* filter, LPCSTR name)
Packit 1fb8d4
{
Packit 1fb8d4
	char* p;
Packit 1fb8d4
	char* q;
Packit 1fb8d4
	int count;
Packit 1fb8d4
	LPSTR names;
Packit 1fb8d4
	int iLevel;
Packit 1fb8d4
	count = 1;
Packit 1fb8d4
Packit 1fb8d4
	if (!name)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit Service 5a9772
	p = (char*)name;
Packit 1fb8d4
Packit 1fb8d4
	if (p)
Packit 1fb8d4
	{
Packit 1fb8d4
		while ((p = strchr(p, '.')) != NULL)
Packit 1fb8d4
		{
Packit 1fb8d4
			count++;
Packit 1fb8d4
			p++;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	names = _strdup(name);
Packit 1fb8d4
Packit 1fb8d4
	if (!names)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	filter->NameCount = count;
Packit Service 5a9772
	filter->Names = (LPSTR*)calloc((count + 1UL), sizeof(LPSTR));
Packit 1fb8d4
Packit 1fb8d4
	if (!filter->Names)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(names);
Packit 1fb8d4
		filter->NameCount = 0;
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	filter->Names[count] = NULL;
Packit 1fb8d4
	count = 0;
Packit Service 5a9772
	p = (char*)names;
Packit 1fb8d4
	filter->Names[count++] = p;
Packit 1fb8d4
	q = strrchr(p, ':');
Packit 1fb8d4
Packit 1fb8d4
	if (!q)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(names);
Packit 1fb8d4
		free(filter->Names);
Packit 1fb8d4
		filter->Names = NULL;
Packit 1fb8d4
		filter->NameCount = 0;
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	*q = '\0';
Packit 1fb8d4
	q++;
Packit 1fb8d4
	iLevel = WLog_ParseLogLevel(q);
Packit 1fb8d4
Packit 1fb8d4
	if (iLevel < 0)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(names);
Packit 1fb8d4
		free(filter->Names);
Packit 1fb8d4
		filter->Names = NULL;
Packit 1fb8d4
		filter->NameCount = 0;
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit Service 5a9772
	filter->Level = (DWORD)iLevel;
Packit 1fb8d4
Packit 1fb8d4
	while ((p = strchr(p, '.')) != NULL)
Packit 1fb8d4
	{
Packit Service 5a9772
		if (count < (int)filter->NameCount)
Packit 1fb8d4
			filter->Names[count++] = p + 1;
Packit 1fb8d4
Packit 1fb8d4
		*p = '\0';
Packit 1fb8d4
		p++;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL WLog_ParseFilters(void)
Packit 1fb8d4
{
Packit 1fb8d4
	LPCSTR filter = "WLOG_FILTER";
Packit 1fb8d4
	BOOL res = FALSE;
Packit 1fb8d4
	char* env;
Packit 1fb8d4
	DWORD nSize;
Packit Service 5a9772
	free(g_Filters);
Packit 1fb8d4
	g_Filters = NULL;
Packit 1fb8d4
	g_FilterCount = 0;
Packit 1fb8d4
	nSize = GetEnvironmentVariableA(filter, NULL, 0);
Packit 1fb8d4
Packit 1fb8d4
	if (nSize < 1)
Packit 1fb8d4
		return TRUE;
Packit 1fb8d4
Packit Service 5a9772
	env = (LPSTR)malloc(nSize);
Packit 1fb8d4
Packit 1fb8d4
	if (!env)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (GetEnvironmentVariableA(filter, env, nSize) == nSize - 1)
Packit 1fb8d4
		res = WLog_AddStringLogFilters(env);
Packit 1fb8d4
Packit 1fb8d4
	free(env);
Packit 1fb8d4
	return res;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
LONG WLog_GetFilterLogLevel(wLog* log)
Packit 1fb8d4
{
Packit 1fb8d4
	DWORD i, j;
Packit 1fb8d4
	BOOL match = FALSE;
Packit 1fb8d4
Packit 1fb8d4
	if (log->FilterLevel >= 0)
Packit 1fb8d4
		return log->FilterLevel;
Packit 1fb8d4
Packit 1fb8d4
	for (i = 0; i < g_FilterCount; i++)
Packit 1fb8d4
	{
Packit 1fb8d4
		for (j = 0; j < g_Filters[i].NameCount; j++)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (j >= log->NameCount)
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			if (_stricmp(g_Filters[i].Names[j], "*") == 0)
Packit 1fb8d4
			{
Packit 1fb8d4
				match = TRUE;
Packit 1fb8d4
				break;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			if (_stricmp(g_Filters[i].Names[j], log->Names[j]) != 0)
Packit 1fb8d4
				break;
Packit 1fb8d4
Packit 1fb8d4
			if (j == (log->NameCount - 1))
Packit 1fb8d4
			{
Packit 1fb8d4
				match = TRUE;
Packit 1fb8d4
				break;
Packit 1fb8d4
			}
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		if (match)
Packit 1fb8d4
			break;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (match)
Packit 1fb8d4
		log->FilterLevel = g_Filters[i].Level;
Packit 1fb8d4
	else
Packit Service 5a9772
		log->FilterLevel = WLOG_FILTER_NOT_FILTERED;
Packit 1fb8d4
Packit 1fb8d4
	return log->FilterLevel;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL WLog_ParseName(wLog* log, LPCSTR name)
Packit 1fb8d4
{
Packit 1fb8d4
	char* p;
Packit 1fb8d4
	int count;
Packit 1fb8d4
	LPSTR names;
Packit 1fb8d4
	count = 1;
Packit Service 5a9772
	p = (char*)name;
Packit 1fb8d4
Packit 1fb8d4
	while ((p = strchr(p, '.')) != NULL)
Packit 1fb8d4
	{
Packit 1fb8d4
		count++;
Packit 1fb8d4
		p++;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	names = _strdup(name);
Packit 1fb8d4
Packit 1fb8d4
	if (!names)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	log->NameCount = count;
Packit Service 5a9772
	log->Names = (LPSTR*)calloc((count + 1UL), sizeof(LPSTR));
Packit 1fb8d4
Packit 1fb8d4
	if (!log->Names)
Packit 1fb8d4
	{
Packit 1fb8d4
		free(names);
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	log->Names[count] = NULL;
Packit 1fb8d4
	count = 0;
Packit Service 5a9772
	p = (char*)names;
Packit 1fb8d4
	log->Names[count++] = p;
Packit 1fb8d4
Packit 1fb8d4
	while ((p = strchr(p, '.')) != NULL)
Packit 1fb8d4
	{
Packit Service 5a9772
		if (count < (int)log->NameCount)
Packit 1fb8d4
			log->Names[count++] = p + 1;
Packit 1fb8d4
Packit 1fb8d4
		*p = '\0';
Packit 1fb8d4
		p++;
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
wLog* WLog_New(LPCSTR name, wLog* rootLogger)
Packit 1fb8d4
{
Packit 1fb8d4
	wLog* log = NULL;
Packit 1fb8d4
	char* env = NULL;
Packit 1fb8d4
	DWORD nSize;
Packit 1fb8d4
	int iLevel;
Packit Service 5a9772
	log = (wLog*)calloc(1, sizeof(wLog));
Packit 1fb8d4
Packit 1fb8d4
	if (!log)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	log->Name = _strdup(name);
Packit 1fb8d4
Packit 1fb8d4
	if (!log->Name)
Packit 1fb8d4
		goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
	if (!WLog_ParseName(log, name))
Packit 1fb8d4
		goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
	log->Parent = rootLogger;
Packit 1fb8d4
	log->ChildrenCount = 0;
Packit 1fb8d4
	log->ChildrenSize = 16;
Packit Service 5a9772
	log->FilterLevel = WLOG_FILTER_NOT_INITIALIZED;
Packit 1fb8d4
Packit Service 5a9772
	if (!(log->Children = (wLog**)calloc(log->ChildrenSize, sizeof(wLog*))))
Packit 1fb8d4
		goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
	log->Appender = NULL;
Packit 1fb8d4
Packit 1fb8d4
	if (rootLogger)
Packit 1fb8d4
	{
Packit 1fb8d4
		log->Level = WLOG_LEVEL_INHERIT;
Packit Service 5a9772
		log->inherit = TRUE;
Packit 1fb8d4
	}
Packit 1fb8d4
	else
Packit 1fb8d4
	{
Packit 1fb8d4
		LPCSTR level = "WLOG_LEVEL";
Packit 1fb8d4
		log->Level = WLOG_INFO;
Packit 1fb8d4
		nSize = GetEnvironmentVariableA(level, NULL, 0);
Packit 1fb8d4
Packit 1fb8d4
		if (nSize)
Packit 1fb8d4
		{
Packit Service 5a9772
			env = (LPSTR)malloc(nSize);
Packit 1fb8d4
Packit 1fb8d4
			if (!env)
Packit 1fb8d4
				goto out_fail;
Packit 1fb8d4
Packit 1fb8d4
			if (GetEnvironmentVariableA(level, env, nSize) != nSize - 1)
Packit 1fb8d4
			{
Packit 1fb8d4
				fprintf(stderr, "%s environment variable changed in my back !\n", level);
Packit 1fb8d4
				free(env);
Packit 1fb8d4
				goto out_fail;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			iLevel = WLog_ParseLogLevel(env);
Packit 1fb8d4
			free(env);
Packit 1fb8d4
Packit 1fb8d4
			if (iLevel >= 0)
Packit Service 5a9772
			{
Packit Service 5a9772
				if (!WLog_SetLogLevel(log, (DWORD)iLevel))
Packit Service 5a9772
					goto out_fail;
Packit Service 5a9772
			}
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	iLevel = WLog_GetFilterLogLevel(log);
Packit 1fb8d4
Packit Service 5a9772
	if (iLevel >= 0)
Packit Service 5a9772
	{
Packit Service 5a9772
		if (!WLog_SetLogLevel(log, (DWORD)iLevel))
Packit Service 5a9772
			goto out_fail;
Packit Service 5a9772
	}
Packit 1fb8d4
Packit 1fb8d4
	return log;
Packit 1fb8d4
out_fail:
Packit 1fb8d4
	free(log->Children);
Packit 1fb8d4
	free(log->Name);
Packit 1fb8d4
	free(log);
Packit 1fb8d4
	return NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
void WLog_Free(wLog* log)
Packit 1fb8d4
{
Packit 1fb8d4
	if (log)
Packit 1fb8d4
	{
Packit 1fb8d4
		if (log->Appender)
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_Appender_Free(log, log->Appender);
Packit 1fb8d4
			log->Appender = NULL;
Packit 1fb8d4
		}
Packit 1fb8d4
Packit 1fb8d4
		free(log->Name);
Packit 1fb8d4
		free(log->Names[0]);
Packit 1fb8d4
		free(log->Names);
Packit 1fb8d4
		free(log->Children);
Packit 1fb8d4
		free(log);
Packit 1fb8d4
	}
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
wLog* WLog_GetRoot(void)
Packit 1fb8d4
{
Packit 1fb8d4
	if (!InitOnceExecuteOnce(&_WLogInitialized, WLog_InitializeRoot, NULL, NULL))
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	return g_RootLog;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static BOOL WLog_AddChild(wLog* parent, wLog* child)
Packit 1fb8d4
{
Packit 1fb8d4
	if (parent->ChildrenCount >= parent->ChildrenSize)
Packit 1fb8d4
	{
Packit 1fb8d4
		wLog** tmp;
Packit 1fb8d4
		parent->ChildrenSize *= 2;
Packit 1fb8d4
Packit 1fb8d4
		if (!parent->ChildrenSize)
Packit 1fb8d4
		{
Packit 1fb8d4
			if (parent->Children)
Packit 1fb8d4
				free(parent->Children);
Packit 1fb8d4
Packit 1fb8d4
			parent->Children = NULL;
Packit 1fb8d4
		}
Packit 1fb8d4
		else
Packit 1fb8d4
		{
Packit Service 5a9772
			tmp = (wLog**)realloc(parent->Children, sizeof(wLog*) * parent->ChildrenSize);
Packit 1fb8d4
Packit 1fb8d4
			if (!tmp)
Packit 1fb8d4
			{
Packit 1fb8d4
				if (parent->Children)
Packit 1fb8d4
					free(parent->Children);
Packit 1fb8d4
Packit 1fb8d4
				parent->Children = NULL;
Packit 1fb8d4
				return FALSE;
Packit 1fb8d4
			}
Packit 1fb8d4
Packit 1fb8d4
			parent->Children = tmp;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	if (!parent->Children)
Packit 1fb8d4
		return FALSE;
Packit 1fb8d4
Packit 1fb8d4
	parent->Children[parent->ChildrenCount++] = child;
Packit 1fb8d4
	child->Parent = parent;
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
static wLog* WLog_FindChild(LPCSTR name)
Packit 1fb8d4
{
Packit 1fb8d4
	DWORD index;
Packit 1fb8d4
	wLog* root;
Packit 1fb8d4
	wLog* child = NULL;
Packit 1fb8d4
	BOOL found = FALSE;
Packit 1fb8d4
	root = WLog_GetRoot();
Packit 1fb8d4
Packit 1fb8d4
	if (!root)
Packit 1fb8d4
		return NULL;
Packit 1fb8d4
Packit 1fb8d4
	for (index = 0; index < root->ChildrenCount; index++)
Packit 1fb8d4
	{
Packit 1fb8d4
		child = root->Children[index];
Packit 1fb8d4
Packit 1fb8d4
		if (strcmp(child->Name, name) == 0)
Packit 1fb8d4
		{
Packit 1fb8d4
			found = TRUE;
Packit 1fb8d4
			break;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return (found) ? child : NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
wLog* WLog_Get(LPCSTR name)
Packit 1fb8d4
{
Packit 1fb8d4
	wLog* log;
Packit 1fb8d4
Packit 1fb8d4
	if (!(log = WLog_FindChild(name)))
Packit 1fb8d4
	{
Packit 1fb8d4
		wLog* root = WLog_GetRoot();
Packit 1fb8d4
Packit 1fb8d4
		if (!root)
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
Packit 1fb8d4
		if (!(log = WLog_New(name, root)))
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
Packit 1fb8d4
		if (!WLog_AddChild(root, log))
Packit 1fb8d4
		{
Packit 1fb8d4
			WLog_Free(log);
Packit 1fb8d4
			return NULL;
Packit 1fb8d4
		}
Packit 1fb8d4
	}
Packit 1fb8d4
Packit 1fb8d4
	return log;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL WLog_Init(void)
Packit 1fb8d4
{
Packit 1fb8d4
	return WLog_GetRoot() != NULL;
Packit 1fb8d4
}
Packit 1fb8d4
Packit 1fb8d4
BOOL WLog_Uninit(void)
Packit 1fb8d4
{
Packit 1fb8d4
	return TRUE;
Packit 1fb8d4
}