all repos — mgba @ 959f66a1a0faff37607a53c4da1ea7b508d6a43a

mGBA Game Boy Advance Emulator

src/core/log.c (view raw)

  1/* Copyright (c) 2013-2016 Jeffrey Pfau
  2 *
  3 * This Source Code Form is subject to the terms of the Mozilla Public
  4 * License, v. 2.0. If a copy of the MPL was not distributed with this
  5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  6#include <mgba/core/log.h>
  7
  8#include <mgba/core/config.h>
  9#include <mgba/core/thread.h>
 10
 11#define MAX_CATEGORY 64
 12
 13static struct mLogger* _defaultLogger = NULL;
 14
 15struct mLogger* mLogGetContext(void) {
 16	struct mLogger* logger = NULL;
 17#ifndef DISABLE_THREADING
 18	logger = mCoreThreadLogger();
 19#endif
 20	if (logger) {
 21		return logger;
 22	}
 23	return _defaultLogger;
 24}
 25
 26void mLogSetDefaultLogger(struct mLogger* logger) {
 27	_defaultLogger = logger;
 28}
 29
 30static int _category = 0;
 31static const char* _categoryNames[MAX_CATEGORY];
 32static const char* _categoryIds[MAX_CATEGORY];
 33
 34int mLogGenerateCategory(const char* name, const char* id) {
 35	if (_category < MAX_CATEGORY) {
 36		_categoryNames[_category] = name;
 37		_categoryIds[_category] = id;
 38	}
 39	++_category;
 40	return _category - 1;
 41}
 42
 43const char* mLogCategoryName(int category) {
 44	if (category < MAX_CATEGORY) {
 45		return _categoryNames[category];
 46	}
 47	return NULL;
 48}
 49
 50const char* mLogCategoryId(int category) {
 51	if (category < MAX_CATEGORY) {
 52		return _categoryIds[category];
 53	}
 54	return NULL;
 55}
 56
 57int mLogCategoryById(const char* id) {
 58	int i;
 59	for (i = 0; i < _category; ++i) {
 60		if (strcmp(_categoryIds[i], id) == 0) {
 61			return i;
 62		}
 63	}
 64	return -1;
 65}
 66
 67void mLog(int category, enum mLogLevel level, const char* format, ...) {
 68	struct mLogger* context = mLogGetContext();
 69	va_list args;
 70	va_start(args, format);
 71	if (context) {
 72		if (!context->filter || mLogFilterTest(context->filter, category, level)) {
 73			context->log(context, category, level, format, args);
 74		}
 75	} else {
 76		printf("%s: ", mLogCategoryName(category));
 77		vprintf(format, args);
 78		printf("\n");
 79	}
 80	va_end(args);
 81}
 82
 83void mLogFilterInit(struct mLogFilter* filter) {
 84	HashTableInit(&filter->categories, 8, NULL);
 85	TableInit(&filter->levels, 8, NULL);
 86}
 87
 88void mLogFilterDeinit(struct mLogFilter* filter) {
 89	HashTableDeinit(&filter->categories);
 90	TableDeinit(&filter->levels);
 91}
 92
 93static void _setFilterLevel(const char* key, const char* value, enum mCoreConfigLevel level, void* user) {
 94	UNUSED(level);
 95	struct mLogFilter* filter = user;
 96	key = strchr(key, '.');
 97	if (!key || !key[1]) {
 98		return;
 99	}
100	if (!value) {
101		return;
102	}
103	++key;
104	char* end;
105	int ivalue = strtol(value, &end, 10);
106	if (ivalue == 0) {
107		ivalue = INT_MIN; // Zero is reserved
108	}
109	if (!end) {
110		return;
111	}
112	mLogFilterSet(filter, key, ivalue);
113}
114
115void mLogFilterLoad(struct mLogFilter* filter, const struct mCoreConfig* config) {
116	mCoreConfigEnumerate(config, "logLevel.", _setFilterLevel, filter);
117	filter->defaultLevels = mLOG_ALL;
118	mCoreConfigGetIntValue(config, "logLevel", &filter->defaultLevels);
119}
120
121void mLogFilterSet(struct mLogFilter* filter, const char* category, int levels) {
122	HashTableInsert(&filter->categories, category, (void*)(intptr_t) levels);
123	// Can't do this eagerly because not all categories are initialized immediately
124	int cat = mLogCategoryById(category);
125	if (cat >= 0) {
126		TableInsert(&filter->levels, cat, (void*)(intptr_t) levels);
127	}
128
129}
130bool mLogFilterTest(struct mLogFilter* filter, int category, enum mLogLevel level) {
131	int value = (int) TableLookup(&filter->levels, category);
132	if (value) {
133		return value & level;
134	}
135	const char* cat = mLogCategoryId(category);
136	if (cat) {
137		value = (int) HashTableLookup(&filter->categories, cat);
138		if (value) {
139			TableInsert(&filter->levels, category, (void*)(intptr_t) value);
140			return value & level;
141		}
142	}
143	return level & filter->defaultLevels;
144}
145
146mLOG_DEFINE_CATEGORY(STATUS, "Status", "core.status")