summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/CMakeLists.txt13
-rw-r--r--src/common/break_points.cpp2
-rw-r--r--src/common/chunk_file.h73
-rw-r--r--src/common/common_funcs.h21
-rw-r--r--src/common/common_paths.h18
-rw-r--r--src/common/common_types.h8
-rw-r--r--src/common/concurrent_ring_buffer.h164
-rw-r--r--src/common/console_listener.cpp319
-rw-r--r--src/common/console_listener.h38
-rw-r--r--src/common/emu_window.h128
-rw-r--r--src/common/extended_trace.cpp46
-rw-r--r--src/common/fifo_queue.h6
-rw-r--r--src/common/file_search.cpp2
-rw-r--r--src/common/file_util.cpp156
-rw-r--r--src/common/file_util.h188
-rw-r--r--src/common/hash.cpp32
-rw-r--r--src/common/linear_disk_cache.h8
-rw-r--r--src/common/log.h126
-rw-r--r--src/common/log_manager.cpp199
-rw-r--r--src/common/log_manager.h166
-rw-r--r--src/common/logging/backend.cpp151
-rw-r--r--src/common/logging/backend.h134
-rw-r--r--src/common/logging/filter.cpp132
-rw-r--r--src/common/logging/filter.h63
-rw-r--r--src/common/logging/log.h115
-rw-r--r--src/common/logging/text_formatter.cpp136
-rw-r--r--src/common/logging/text_formatter.h41
-rw-r--r--src/common/math_util.cpp14
-rw-r--r--src/common/math_util.h9
-rw-r--r--src/common/mem_arena.cpp46
-rw-r--r--src/common/memory_util.cpp20
-rw-r--r--src/common/misc.cpp4
-rw-r--r--src/common/msg_handler.cpp2
-rw-r--r--src/common/msg_handler.h42
-rw-r--r--src/common/platform.h2
-rw-r--r--src/common/scope_exit.h37
-rw-r--r--src/common/string_util.cpp190
-rw-r--r--src/common/string_util.h25
-rw-r--r--src/common/symbols.cpp4
-rw-r--r--src/common/symbols.h2
-rw-r--r--src/common/thread.cpp6
-rw-r--r--src/common/thread.h11
-rw-r--r--src/common/thread_queue_list.h16
-rw-r--r--src/common/timer.cpp6
-rw-r--r--src/common/utf8.cpp24
45 files changed, 1620 insertions, 1325 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 9d5a90762..15989708d 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -3,14 +3,15 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in" "${CMAKE_CURRENT_SOU
set(SRCS
break_points.cpp
- console_listener.cpp
emu_window.cpp
extended_trace.cpp
file_search.cpp
file_util.cpp
hash.cpp
key_map.cpp
- log_manager.cpp
+ logging/filter.cpp
+ logging/text_formatter.cpp
+ logging/backend.cpp
math_util.cpp
mem_arena.cpp
memory_util.cpp
@@ -32,7 +33,7 @@ set(HEADERS
common_funcs.h
common_paths.h
common_types.h
- console_listener.h
+ concurrent_ring_buffer.h
cpu_detect.h
debug_interface.h
emu_window.h
@@ -44,13 +45,17 @@ set(HEADERS
key_map.h
linear_disk_cache.h
log.h
- log_manager.h
+ logging/text_formatter.h
+ logging/filter.h
+ logging/log.h
+ logging/backend.h
math_util.h
mem_arena.h
memory_util.h
msg_handler.h
platform.h
scm_rev.h
+ scope_exit.h
string_util.h
swap.h
symbols.h
diff --git a/src/common/break_points.cpp b/src/common/break_points.cpp
index 25528b864..587dbf40a 100644
--- a/src/common/break_points.cpp
+++ b/src/common/break_points.cpp
@@ -180,7 +180,7 @@ void TMemCheck::Action(DebugInterface *debug_interface, u32 iValue, u32 addr,
{
if (Log)
{
- INFO_LOG(MEMMAP, "CHK %08x (%s) %s%i %0*x at %08x (%s)",
+ LOG_DEBUG(Debug_Breakpoint, "CHK %08x (%s) %s%i %0*x at %08x (%s)",
pc, debug_interface->getDescription(pc).c_str(),
write ? "Write" : "Read", size*8, size*2, iValue, addr,
debug_interface->getDescription(addr).c_str()
diff --git a/src/common/chunk_file.h b/src/common/chunk_file.h
index dc8ac1fd9..39a14dc81 100644
--- a/src/common/chunk_file.h
+++ b/src/common/chunk_file.h
@@ -51,7 +51,7 @@ public:
PointerWrapSection(PointerWrap &p, int ver, const char *title) : p_(p), ver_(ver), title_(title) {
}
~PointerWrapSection();
-
+
bool operator == (const int &v) const { return ver_ == v; }
bool operator != (const int &v) const { return ver_ != v; }
bool operator <= (const int &v) const { return ver_ <= v; }
@@ -154,7 +154,7 @@ public:
Do(foundVersion);
if (error == ERROR_FAILURE || foundVersion < minVer || foundVersion > ver) {
- WARN_LOG(COMMON, "Savestate failure: wrong version %d found for %s", foundVersion, title);
+ LOG_ERROR(Common, "Savestate failure: wrong version %d found for %s", foundVersion, title);
SetError(ERROR_FAILURE);
return PointerWrapSection(*this, -1, title);
}
@@ -178,7 +178,14 @@ public:
case MODE_READ: if (memcmp(data, *ptr, size) != 0) return false; break;
case MODE_WRITE: memcpy(*ptr, data, size); break;
case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything
- case MODE_VERIFY: for(int i = 0; i < size; i++) _dbg_assert_msg_(COMMON, ((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); break;
+ case MODE_VERIFY:
+ for (int i = 0; i < size; i++) {
+ _dbg_assert_msg_(Common, ((u8*)data)[i] == (*ptr)[i],
+ "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n",
+ ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i],
+ (*ptr)[i], (*ptr)[i], &(*ptr)[i]);
+ }
+ break;
default: break; // throw an error?
}
(*ptr) += size;
@@ -191,12 +198,19 @@ public:
case MODE_READ: memcpy(data, *ptr, size); break;
case MODE_WRITE: memcpy(*ptr, data, size); break;
case MODE_MEASURE: break; // MODE_MEASURE - don't need to do anything
- case MODE_VERIFY: for(int i = 0; i < size; i++) _dbg_assert_msg_(COMMON, ((u8*)data)[i] == (*ptr)[i], "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n", ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i], (*ptr)[i], (*ptr)[i], &(*ptr)[i]); break;
+ case MODE_VERIFY:
+ for (int i = 0; i < size; i++) {
+ _dbg_assert_msg_(Common, ((u8*)data)[i] == (*ptr)[i],
+ "Savestate verification failure: %d (0x%X) (at %p) != %d (0x%X) (at %p).\n",
+ ((u8*)data)[i], ((u8*)data)[i], &((u8*)data)[i],
+ (*ptr)[i], (*ptr)[i], &(*ptr)[i]);
+ }
+ break;
default: break; // throw an error?
}
(*ptr) += size;
}
-
+
template<class K, class T>
void Do(std::map<K, T *> &x)
{
@@ -204,11 +218,11 @@ public:
{
for (auto it = x.begin(), end = x.end(); it != end; ++it)
{
- if (it->second != NULL)
+ if (it->second != nullptr)
delete it->second;
}
}
- T *dv = NULL;
+ T *dv = nullptr;
DoMap(x, dv);
}
@@ -264,11 +278,11 @@ public:
{
for (auto it = x.begin(), end = x.end(); it != end; ++it)
{
- if (it->second != NULL)
+ if (it->second != nullptr)
delete it->second;
}
}
- T *dv = NULL;
+ T *dv = nullptr;
DoMultimap(x, dv);
}
@@ -320,7 +334,7 @@ public:
template<class T>
void Do(std::vector<T *> &x)
{
- T *dv = NULL;
+ T *dv = nullptr;
DoVector(x, dv);
}
@@ -364,12 +378,12 @@ public:
if (vec_size > 0)
DoArray(&x[0], vec_size);
}
-
+
// Store deques.
template<class T>
void Do(std::deque<T *> &x)
{
- T *dv = NULL;
+ T *dv = nullptr;
DoDeque(x, dv);
}
@@ -395,7 +409,7 @@ public:
template<class T>
void Do(std::list<T *> &x)
{
- T *dv = NULL;
+ T *dv = nullptr;
Do(x, dv);
}
@@ -433,7 +447,7 @@ public:
{
for (auto it = x.begin(), end = x.end(); it != end; ++it)
{
- if (*it != NULL)
+ if (*it != nullptr)
delete *it;
}
}
@@ -476,26 +490,31 @@ public:
break;
default:
- ERROR_LOG(COMMON, "Savestate error: invalid mode %d.", mode);
+ LOG_ERROR(Common, "Savestate error: invalid mode %d.", mode);
}
}
// Store strings.
- void Do(std::string &x)
+ void Do(std::string &x)
{
int stringLen = (int)x.length() + 1;
Do(stringLen);
-
+
switch (mode) {
case MODE_READ: x = (char*)*ptr; break;
case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break;
case MODE_MEASURE: break;
- case MODE_VERIFY: _dbg_assert_msg_(COMMON, !strcmp(x.c_str(), (char*)*ptr), "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n", x.c_str(), (char*)*ptr, ptr); break;
+ case MODE_VERIFY:
+ _dbg_assert_msg_(Common,
+ !strcmp(x.c_str(), (char*)*ptr),
+ "Savestate verification failure: \"%s\" != \"%s\" (at %p).\n",
+ x.c_str(), (char*)*ptr, ptr);
+ break;
}
(*ptr) += stringLen;
}
- void Do(std::wstring &x)
+ void Do(std::wstring &x)
{
int stringLen = sizeof(wchar_t)*((int)x.length() + 1);
Do(stringLen);
@@ -504,7 +523,11 @@ public:
case MODE_READ: x = (wchar_t*)*ptr; break;
case MODE_WRITE: memcpy(*ptr, x.c_str(), stringLen); break;
case MODE_MEASURE: break;
- case MODE_VERIFY: _dbg_assert_msg_(COMMON, x == (wchar_t*)*ptr, "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n", x.c_str(), (wchar_t*)*ptr, ptr); break;
+ case MODE_VERIFY:
+ _dbg_assert_msg_(Common, x == (wchar_t*)*ptr,
+ "Savestate verification failure: \"%ls\" != \"%ls\" (at %p).\n",
+ x.c_str(), (wchar_t*)*ptr, ptr);
+ break;
}
(*ptr) += stringLen;
}
@@ -518,7 +541,7 @@ public:
void DoClass(T *&x) {
if (mode == MODE_READ)
{
- if (x != NULL)
+ if (x != nullptr)
delete x;
x = new T();
}
@@ -534,7 +557,7 @@ public:
void Do(T &x) {
DoHelper<T>::Do(this, x);
}
-
+
template<class T>
void DoPOD(T &x) {
DoHelper<T>::Do(this, x);
@@ -567,7 +590,7 @@ public:
{
if (mode == MODE_READ)
{
- cur->next = 0;
+ cur->next = nullptr;
list_cur = cur;
if (prev)
prev->next = cur;
@@ -586,13 +609,13 @@ public:
if (mode == MODE_READ)
{
if (prev)
- prev->next = 0;
+ prev->next = nullptr;
if (list_end)
*list_end = prev;
if (list_cur)
{
if (list_start == list_cur)
- list_start = 0;
+ list_start = nullptr;
do
{
LinkedListItem<T>* next = list_cur->next;
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index c18afe119..67b3679b0 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -4,6 +4,9 @@
#pragma once
+#include "common_types.h"
+#include <cstdlib>
+
#ifdef _WIN32
#define SLEEP(x) Sleep(x)
#else
@@ -17,7 +20,7 @@ template<> struct CompileTimeAssert<true> {};
#define b2(x) ( (x) | ( (x) >> 1) )
#define b4(x) ( b2(x) | ( b2(x) >> 2) )
#define b8(x) ( b4(x) | ( b4(x) >> 4) )
-#define b16(x) ( b8(x) | ( b8(x) >> 8) )
+#define b16(x) ( b8(x) | ( b8(x) >> 8) )
#define b32(x) (b16(x) | (b16(x) >>16) )
#define ROUND_UP_POW2(x) (b32(x - 1) + 1)
@@ -73,18 +76,20 @@ inline u64 _rotr64(u64 x, unsigned int shift){
}
#else // WIN32
+#include <locale.h>
+
// Function Cross-Compatibility
#define strcasecmp _stricmp
#define strncasecmp _strnicmp
#define unlink _unlink
#define snprintf _snprintf
#define vscprintf _vscprintf
-
+
// Locale Cross-Compatibility
#define locale_t _locale_t
#define freelocale _free_locale
#define newlocale(mask, locale, base) _create_locale(mask, locale)
-
+
#define LC_GLOBAL_LOCALE ((locale_t)-1)
#define LC_ALL_MASK LC_ALL
#define LC_COLLATE_MASK LC_COLLATE
@@ -92,7 +97,7 @@ inline u64 _rotr64(u64 x, unsigned int shift){
#define LC_MONETARY_MASK LC_MONETARY
#define LC_NUMERIC_MASK LC_NUMERIC
#define LC_TIME_MASK LC_TIME
-
+
inline locale_t uselocale(locale_t new_locale)
{
// Retrieve the current per thread locale setting
@@ -106,7 +111,7 @@ inline u64 _rotr64(u64 x, unsigned int shift){
// Restore the global locale
_configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
}
- else if(new_locale != NULL)
+ else if(new_locale != nullptr)
{
// Configure the thread to set the locale only for this thread
_configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
@@ -168,8 +173,8 @@ inline u16 swap16(u16 _data) {return _byteswap_ushort(_data);}
inline u32 swap32(u32 _data) {return _byteswap_ulong (_data);}
inline u64 swap64(u64 _data) {return _byteswap_uint64(_data);}
#elif _M_ARM
-inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;}
-inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;}
+inline u16 swap16 (u16 _data) { u32 data = _data; __asm__ ("rev16 %0, %1\n" : "=l" (data) : "l" (data)); return (u16)data;}
+inline u32 swap32 (u32 _data) {__asm__ ("rev %0, %1\n" : "=l" (_data) : "l" (_data)); return _data;}
inline u64 swap64(u64 _data) {return ((u64)swap32(_data) << 32) | swap32(_data >> 32);}
#elif __linux__
inline u16 swap16(u16 _data) {return bswap_16(_data);}
@@ -226,7 +231,7 @@ template <typename T>
inline T FromBigEndian(T data)
{
//static_assert(std::is_arithmetic<T>::value, "function only makes sense with arithmetic types");
-
+
swap<sizeof(data)>(reinterpret_cast<u8*>(&data));
return data;
}
diff --git a/src/common/common_paths.h b/src/common/common_paths.h
index ae08d082a..a86889756 100644
--- a/src/common/common_paths.h
+++ b/src/common/common_paths.h
@@ -29,19 +29,6 @@
#endif
#endif
-// Shared data dirs (Sys and shared User for linux)
-#ifdef _WIN32
- #define SYSDATA_DIR "sys"
-#else
- #ifdef DATA_DIR
- #define SYSDATA_DIR DATA_DIR "sys"
- #define SHARED_USER_DIR DATA_DIR USERDATA_DIR DIR_SEP
- #else
- #define SYSDATA_DIR "sys"
- #define SHARED_USER_DIR ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP
- #endif
-#endif
-
// Dirs in both User and Sys
#define EUR_DIR "EUR"
#define USA_DIR "USA"
@@ -53,6 +40,8 @@
#define MAPS_DIR "maps"
#define CACHE_DIR "cache"
#define SDMC_DIR "sdmc"
+#define SAVEDATA_DIR "savedata"
+#define SYSDATA_DIR "sysdata"
#define SHADERCACHE_DIR "shader_cache"
#define STATESAVES_DIR "state_saves"
#define SCREENSHOTS_DIR "screenShots"
@@ -70,6 +59,9 @@
#define DEBUGGER_CONFIG "debugger.ini"
#define LOGGER_CONFIG "logger.ini"
+// Sys files
+#define SHARED_FONT "shared_font.bin"
+
// Files in the directory returned by GetUserPath(D_LOGS_IDX)
#define MAIN_LOG "emu.log"
diff --git a/src/common/common_types.h b/src/common/common_types.h
index 7ce6b2240..c74c74f0f 100644
--- a/src/common/common_types.h
+++ b/src/common/common_types.h
@@ -22,7 +22,7 @@
* http://code.google.com/p/gekko-gc-emu/
*/
-#pragma once
+#pragma once
#include <cmath>
#include <cstdint>
@@ -41,12 +41,10 @@ typedef std::int64_t s64; ///< 64-bit signed int
typedef float f32; ///< 32-bit floating point
typedef double f64; ///< 64-bit floating point
-#include "common/common.h"
-
/// Union for fast 16-bit type casting
union t16 {
- u8 _u8[2]; ///< 8-bit unsigned char(s)
- u16 _u16; ///< 16-bit unsigned shorts(s)
+ u8 _u8[2]; ///< 8-bit unsigned char(s)
+ u16 _u16; ///< 16-bit unsigned shorts(s)
};
/// Union for fast 32-bit type casting
diff --git a/src/common/concurrent_ring_buffer.h b/src/common/concurrent_ring_buffer.h
new file mode 100644
index 000000000..2951d93db
--- /dev/null
+++ b/src/common/concurrent_ring_buffer.h
@@ -0,0 +1,164 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <array>
+#include <condition_variable>
+#include <cstdint>
+#include <mutex>
+#include <thread>
+
+#include "common/common.h" // for NonCopyable
+#include "common/log.h" // for _dbg_assert_
+
+namespace Common {
+
+/**
+ * A MPMC (Multiple-Producer Multiple-Consumer) concurrent ring buffer. This data structure permits
+ * multiple threads to push and pop from a queue of bounded size.
+ */
+template <typename T, size_t ArraySize>
+class ConcurrentRingBuffer : private NonCopyable {
+public:
+ /// Value returned by the popping functions when the queue has been closed.
+ static const size_t QUEUE_CLOSED = -1;
+
+ ConcurrentRingBuffer() {}
+
+ ~ConcurrentRingBuffer() {
+ // If for whatever reason the queue wasn't completely drained, destroy the left over items.
+ for (size_t i = reader_index, end = writer_index; i != end; i = (i + 1) % ArraySize) {
+ Data()[i].~T();
+ }
+ }
+
+ /**
+ * Pushes a value to the queue. If the queue is full, this method will block. Does nothing if
+ * the queue is closed.
+ */
+ void Push(T val) {
+ std::unique_lock<std::mutex> lock(mutex);
+ if (closed) {
+ return;
+ }
+
+ // If the buffer is full, wait
+ writer.wait(lock, [&]{
+ return (writer_index + 1) % ArraySize != reader_index;
+ });
+
+ T* item = &Data()[writer_index];
+ new (item) T(std::move(val));
+
+ writer_index = (writer_index + 1) % ArraySize;
+
+ // Wake up waiting readers
+ lock.unlock();
+ reader.notify_one();
+ }
+
+ /**
+ * Pops up to `dest_len` items from the queue, storing them in `dest`. This function will not
+ * block, and might return 0 values if there are no elements in the queue when it is called.
+ *
+ * @return The number of elements stored in `dest`. If the queue has been closed, returns
+ * `QUEUE_CLOSED`.
+ */
+ size_t Pop(T* dest, size_t dest_len) {
+ std::unique_lock<std::mutex> lock(mutex);
+ if (closed && !CanRead()) {
+ return QUEUE_CLOSED;
+ }
+ return PopInternal(dest, dest_len);
+ }
+
+ /**
+ * Pops up to `dest_len` items from the queue, storing them in `dest`. This function will block
+ * if there are no elements in the queue when it is called.
+ *
+ * @return The number of elements stored in `dest`. If the queue has been closed, returns
+ * `QUEUE_CLOSED`.
+ */
+ size_t BlockingPop(T* dest, size_t dest_len) {
+ std::unique_lock<std::mutex> lock(mutex);
+ if (closed && !CanRead()) {
+ return QUEUE_CLOSED;
+ }
+
+ while (!CanRead()) {
+ reader.wait(lock);
+ if (closed && !CanRead()) {
+ return QUEUE_CLOSED;
+ }
+ }
+ _dbg_assert_(Common, CanRead());
+ return PopInternal(dest, dest_len);
+ }
+
+ /**
+ * Closes the queue. After calling this method, `Push` operations won't have any effect, and
+ * `PopMany` and `PopManyBlock` will start returning `QUEUE_CLOSED`. This is intended to allow
+ * a graceful shutdown of all consumers.
+ */
+ void Close() {
+ std::unique_lock<std::mutex> lock(mutex);
+ closed = true;
+ // We need to wake up any reader that are waiting for an item that will never come.
+ lock.unlock();
+ reader.notify_all();
+ }
+
+ /// Returns true if `Close()` has been called.
+ bool IsClosed() const {
+ return closed;
+ }
+
+private:
+ size_t PopInternal(T* dest, size_t dest_len) {
+ size_t output_count = 0;
+ while (output_count < dest_len && CanRead()) {
+ _dbg_assert_(Common, CanRead());
+
+ T* item = &Data()[reader_index];
+ T out_val = std::move(*item);
+ item->~T();
+
+ size_t prev_index = (reader_index + ArraySize - 1) % ArraySize;
+ reader_index = (reader_index + 1) % ArraySize;
+ if (writer_index == prev_index) {
+ writer.notify_one();
+ }
+ dest[output_count++] = std::move(out_val);
+ }
+ return output_count;
+ }
+
+ bool CanRead() const {
+ return reader_index != writer_index;
+ }
+
+ T* Data() {
+ return static_cast<T*>(static_cast<void*>(&storage));
+ }
+
+ /// Storage for entries
+ typename std::aligned_storage<ArraySize * sizeof(T),
+ std::alignment_of<T>::value>::type storage;
+
+ /// Data is valid in the half-open interval [reader, writer). If they are `QUEUE_CLOSED` then the
+ /// queue has been closed.
+ size_t writer_index = 0, reader_index = 0;
+ // True if the queue has been closed.
+ bool closed = false;
+
+ /// Mutex that protects the entire data structure.
+ std::mutex mutex;
+ /// Signaling wakes up reader which is waiting for storage to be non-empty.
+ std::condition_variable reader;
+ /// Signaling wakes up writer which is waiting for storage to be non-full.
+ std::condition_variable writer;
+};
+
+} // namespace
diff --git a/src/common/console_listener.cpp b/src/common/console_listener.cpp
deleted file mode 100644
index 53f20d754..000000000
--- a/src/common/console_listener.cpp
+++ /dev/null
@@ -1,319 +0,0 @@
-// Copyright 2013 Dolphin Emulator Project
-// Licensed under GPLv2
-// Refer to the license.txt file included.
-
-#include <algorithm>
-
-#ifdef _WIN32
-#include <windows.h>
-#include <array>
-#endif
-
-#include "common/common.h"
-#include "common/log_manager.h" // Common
-#include "common/console_listener.h" // Common
-
-ConsoleListener::ConsoleListener()
-{
-#ifdef _WIN32
- hConsole = NULL;
- bUseColor = true;
-#else
- bUseColor = isatty(fileno(stdout));
-#endif
-}
-
-ConsoleListener::~ConsoleListener()
-{
- Close();
-}
-
-// 100, 100, "Dolphin Log Console"
-// Open console window - width and height is the size of console window
-// Name is the window title
-void ConsoleListener::Open(bool Hidden, int Width, int Height, const char *Title)
-{
-#ifdef _WIN32
- if (!GetConsoleWindow())
- {
- // Open the console window and create the window handle for GetStdHandle()
- AllocConsole();
- // Hide
- if (Hidden) ShowWindow(GetConsoleWindow(), SW_HIDE);
- // Save the window handle that AllocConsole() created
- hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
- // Set the console window title
- SetConsoleTitle(Common::UTF8ToTStr(Title).c_str());
- // Set letter space
- LetterSpace(80, 4000);
- //MoveWindow(GetConsoleWindow(), 200,200, 800,800, true);
- }
- else
- {
- hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
- }
-#endif
-}
-
-void ConsoleListener::UpdateHandle()
-{
-#ifdef _WIN32
- hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
-#endif
-}
-
-// Close the console window and close the eventual file handle
-void ConsoleListener::Close()
-{
-#ifdef _WIN32
- if (hConsole == NULL)
- return;
- FreeConsole();
- hConsole = NULL;
-#else
- fflush(NULL);
-#endif
-}
-
-bool ConsoleListener::IsOpen()
-{
-#ifdef _WIN32
- return (hConsole != NULL);
-#else
- return true;
-#endif
-}
-
-/*
- LetterSpace: SetConsoleScreenBufferSize and SetConsoleWindowInfo are
- dependent on each other, that's the reason for the additional checks.
-*/
-void ConsoleListener::BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst)
-{
-#ifdef _WIN32
- BOOL SB, SW;
- if (BufferFirst)
- {
- // Change screen buffer size
- COORD Co = {BufferWidth, BufferHeight};
- SB = SetConsoleScreenBufferSize(hConsole, Co);
- // Change the screen buffer window size
- SMALL_RECT coo = {0,0,ScreenWidth, ScreenHeight}; // top, left, right, bottom
- SW = SetConsoleWindowInfo(hConsole, TRUE, &coo);
- }
- else
- {
- // Change the screen buffer window size
- SMALL_RECT coo = {0,0, ScreenWidth, ScreenHeight}; // top, left, right, bottom
- SW = SetConsoleWindowInfo(hConsole, TRUE, &coo);
- // Change screen buffer size
- COORD Co = {BufferWidth, BufferHeight};
- SB = SetConsoleScreenBufferSize(hConsole, Co);
- }
-#endif
-}
-void ConsoleListener::LetterSpace(int Width, int Height)
-{
-#ifdef _WIN32
- // Get console info
- CONSOLE_SCREEN_BUFFER_INFO ConInfo;
- GetConsoleScreenBufferInfo(hConsole, &ConInfo);
-
- //
- int OldBufferWidth = ConInfo.dwSize.X;
- int OldBufferHeight = ConInfo.dwSize.Y;
- int OldScreenWidth = (ConInfo.srWindow.Right - ConInfo.srWindow.Left);
- int OldScreenHeight = (ConInfo.srWindow.Bottom - ConInfo.srWindow.Top);
- //
- int NewBufferWidth = Width;
- int NewBufferHeight = Height;
- int NewScreenWidth = NewBufferWidth - 1;
- int NewScreenHeight = OldScreenHeight;
-
- // Width
- BufferWidthHeight(NewBufferWidth, OldBufferHeight, NewScreenWidth, OldScreenHeight, (NewBufferWidth > OldScreenWidth-1));
- // Height
- BufferWidthHeight(NewBufferWidth, NewBufferHeight, NewScreenWidth, NewScreenHeight, (NewBufferHeight > OldScreenHeight-1));
-
- // Resize the window too
- //MoveWindow(GetConsoleWindow(), 200,200, (Width*8 + 50),(NewScreenHeight*12 + 200), true);
-#endif
-}
-#ifdef _WIN32
-COORD ConsoleListener::GetCoordinates(int BytesRead, int BufferWidth)
-{
- COORD Ret = {0, 0};
- // Full rows
- int Step = (int)floor((float)BytesRead / (float)BufferWidth);
- Ret.Y += Step;
- // Partial row
- Ret.X = BytesRead - (BufferWidth * Step);
- return Ret;
-}
-#endif
-void ConsoleListener::PixelSpace(int Left, int Top, int Width, int Height, bool Resize)
-{
-#ifdef _WIN32
- // Check size
- if (Width < 8 || Height < 12) return;
-
- bool DBef = true;
- bool DAft = true;
- std::string SLog = "";
-
- const HWND hWnd = GetConsoleWindow();
- const HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
-
- // Get console info
- CONSOLE_SCREEN_BUFFER_INFO ConInfo;
- GetConsoleScreenBufferInfo(hConsole, &ConInfo);
- DWORD BufferSize = ConInfo.dwSize.X * ConInfo.dwSize.Y;
-
- // ---------------------------------------------------------------------
- // Save the current text
- // ------------------------
- DWORD cCharsRead = 0;
- COORD coordScreen = { 0, 0 };
-
- static const int MAX_BYTES = 1024 * 16;
-
- std::vector<std::array<TCHAR, MAX_BYTES>> Str;
- std::vector<std::array<WORD, MAX_BYTES>> Attr;
-
- // ReadConsoleOutputAttribute seems to have a limit at this level
- static const int ReadBufferSize = MAX_BYTES - 32;
-
- DWORD cAttrRead = ReadBufferSize;
- DWORD BytesRead = 0;
- while (BytesRead < BufferSize)
- {
- Str.resize(Str.size() + 1);
- if (!ReadConsoleOutputCharacter(hConsole, Str.back().data(), ReadBufferSize, coordScreen, &cCharsRead))
- SLog += Common::StringFromFormat("WriteConsoleOutputCharacter error");
-
- Attr.resize(Attr.size() + 1);
- if (!ReadConsoleOutputAttribute(hConsole, Attr.back().data(), ReadBufferSize, coordScreen, &cAttrRead))
- SLog += Common::StringFromFormat("WriteConsoleOutputAttribute error");
-
- // Break on error
- if (cAttrRead == 0) break;
- BytesRead += cAttrRead;
- coordScreen = GetCoordinates(BytesRead, ConInfo.dwSize.X);
- }
- // Letter space
- int LWidth = (int)(floor((float)Width / 8.0f) - 1.0f);
- int LHeight = (int)(floor((float)Height / 12.0f) - 1.0f);
- int LBufWidth = LWidth + 1;
- int LBufHeight = (int)floor((float)BufferSize / (float)LBufWidth);
- // Change screen buffer size
- LetterSpace(LBufWidth, LBufHeight);
-
-
- ClearScreen(true);
- coordScreen.Y = 0;
- coordScreen.X = 0;
- DWORD cCharsWritten = 0;
-
- int BytesWritten = 0;
- DWORD cAttrWritten = 0;
- for (size_t i = 0; i < Attr.size(); i++)
- {
- if (!WriteConsoleOutputCharacter(hConsole, Str[i].data(), ReadBufferSize, coordScreen, &cCharsWritten))
- SLog += Common::StringFromFormat("WriteConsoleOutputCharacter error");
- if (!WriteConsoleOutputAttribute(hConsole, Attr[i].data(), ReadBufferSize, coordScreen, &cAttrWritten))
- SLog += Common::StringFromFormat("WriteConsoleOutputAttribute error");
-
- BytesWritten += cAttrWritten;
- coordScreen = GetCoordinates(BytesWritten, LBufWidth);
- }
-
- const int OldCursor = ConInfo.dwCursorPosition.Y * ConInfo.dwSize.X + ConInfo.dwCursorPosition.X;
- COORD Coo = GetCoordinates(OldCursor, LBufWidth);
- SetConsoleCursorPosition(hConsole, Coo);
-
- if (SLog.length() > 0) Log(LogTypes::LNOTICE, SLog.c_str());
-
- // Resize the window too
- if (Resize) MoveWindow(GetConsoleWindow(), Left,Top, (Width + 100),Height, true);
-#endif
-}
-
-void ConsoleListener::Log(LogTypes::LOG_LEVELS Level, const char *Text)
-{
-#if defined(_WIN32)
- WORD Color;
-
- switch (Level)
- {
- case OS_LEVEL: // light yellow
- Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY;
- break;
- case NOTICE_LEVEL: // light green
- Color = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
- break;
- case ERROR_LEVEL: // light red
- Color = FOREGROUND_RED | FOREGROUND_INTENSITY;
- break;
- case WARNING_LEVEL: // light purple
- Color = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
- break;
- case INFO_LEVEL: // cyan
- Color = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
- break;
- case DEBUG_LEVEL: // gray
- Color = FOREGROUND_INTENSITY;
- break;
- default: // off-white
- Color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE;
- break;
- }
- SetConsoleTextAttribute(hConsole, Color);
- printf(Text);
-#else
- char ColorAttr[16] = "";
- char ResetAttr[16] = "";
-
- if (bUseColor)
- {
- strcpy(ResetAttr, "\033[0m");
- switch (Level)
- {
- case NOTICE_LEVEL: // light green
- strcpy(ColorAttr, "\033[92m");
- break;
- case ERROR_LEVEL: // light red
- strcpy(ColorAttr, "\033[91m");
- break;
- case WARNING_LEVEL: // light yellow
- strcpy(ColorAttr, "\033[93m");
- break;
- default:
- break;
- }
- }
- fprintf(stderr, "%s%s%s", ColorAttr, Text, ResetAttr);
-#endif
-}
-// Clear console screen
-void ConsoleListener::ClearScreen(bool Cursor)
-{
-#if defined(_WIN32)
- COORD coordScreen = { 0, 0 };
- DWORD cCharsWritten;
- CONSOLE_SCREEN_BUFFER_INFO csbi;
- DWORD dwConSize;
-
- HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
-
- GetConsoleScreenBufferInfo(hConsole, &csbi);
- dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
- // Write space to the entire console
- FillConsoleOutputCharacter(hConsole, TEXT(' '), dwConSize, coordScreen, &cCharsWritten);
- GetConsoleScreenBufferInfo(hConsole, &csbi);
- FillConsoleOutputAttribute(hConsole, csbi.wAttributes, dwConSize, coordScreen, &cCharsWritten);
- // Reset cursor
- if (Cursor) SetConsoleCursorPosition(hConsole, coordScreen);
-#endif
-}
-
-
diff --git a/src/common/console_listener.h b/src/common/console_listener.h
deleted file mode 100644
index ebd90a105..000000000
--- a/src/common/console_listener.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2013 Dolphin Emulator Project
-// Licensed under GPLv2
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "common/log_manager.h"
-
-#ifdef _WIN32
-#include <windows.h>
-#endif
-
-class ConsoleListener : public LogListener
-{
-public:
- ConsoleListener();
- ~ConsoleListener();
-
- void Open(bool Hidden = false, int Width = 100, int Height = 100, const char * Name = "Console");
- void UpdateHandle();
- void Close();
- bool IsOpen();
- void LetterSpace(int Width, int Height);
- void BufferWidthHeight(int BufferWidth, int BufferHeight, int ScreenWidth, int ScreenHeight, bool BufferFirst);
- void PixelSpace(int Left, int Top, int Width, int Height, bool);
-#ifdef _WIN32
- COORD GetCoordinates(int BytesRead, int BufferWidth);
-#endif
- void Log(LogTypes::LOG_LEVELS, const char *Text) override;
- void ClearScreen(bool Cursor = true);
-
-private:
-#ifdef _WIN32
- HWND GetHwnd(void);
- HANDLE hConsole;
-#endif
- bool bUseColor;
-};
diff --git a/src/common/emu_window.h b/src/common/emu_window.h
index 4d09acb8b..4cb94fed1 100644
--- a/src/common/emu_window.h
+++ b/src/common/emu_window.h
@@ -9,17 +9,33 @@
#include "common/string_util.h"
#include "common/key_map.h"
-// Abstraction class used to provide an interface between emulation code and the frontend (e.g. SDL,
-// QGLWidget, GLFW, etc...)
+/**
+ * Abstraction class used to provide an interface between emulation code and the frontend
+ * (e.g. SDL, QGLWidget, GLFW, etc...).
+ *
+ * Design notes on the interaction between EmuWindow and the emulation core:
+ * - Generally, decisions on anything visible to the user should be left up to the GUI.
+ * For example, the emulation core should not try to dictate some window title or size.
+ * This stuff is not the core's business and only causes problems with regards to thread-safety
+ * anyway.
+ * - Under certain circumstances, it may be desirable for the core to politely request the GUI
+ * to set e.g. a minimum window size. However, the GUI should always be free to ignore any
+ * such hints.
+ * - EmuWindow may expose some of its state as read-only to the emulation core, however care
+ * should be taken to make sure the provided information is self-consistent. This requires
+ * some sort of synchronization (most of this is still a TODO).
+ * - DO NOT TREAT THIS CLASS AS A GUI TOOLKIT ABSTRACTION LAYER. That's not what it is. Please
+ * re-read the upper points again and think about it if you don't see this.
+ */
class EmuWindow
{
-
public:
- /// Data structure to store an emuwindow configuration
+ /// Data structure to store emuwindow configuration
struct WindowConfig {
bool fullscreen;
int res_width;
int res_height;
+ std::pair<unsigned,unsigned> min_client_area_size;
};
/// Swap buffers to display the next frame
@@ -42,52 +58,96 @@ public:
/// Signals a key release action to the HID module
static void KeyReleased(KeyMap::HostDeviceKey key);
- WindowConfig GetConfig() const {
- return m_config;
+ /**
+ * Returns currently active configuration.
+ * @note Accesses to the returned object need not be consistent because it may be modified in another thread
+ */
+ const WindowConfig& GetActiveConfig() const {
+ return active_config;
}
+ /**
+ * Requests the internal configuration to be replaced by the specified argument at some point in the future.
+ * @note This method is thread-safe, because it delays configuration changes to the GUI event loop. Hence there is no guarantee on when the requested configuration will be active.
+ */
void SetConfig(const WindowConfig& val) {
- m_config = val;
- }
-
- int GetClientAreaWidth() const {
- return m_client_area_width;
+ config = val;
}
- void SetClientAreaWidth(const int val) {
- m_client_area_width = val;
+ /**
+ * Gets the framebuffer size in pixels.
+ * @note This method is thread-safe
+ */
+ const std::pair<unsigned,unsigned> GetFramebufferSize() const {
+ return framebuffer_size;
}
- int GetClientAreaHeight() const {
- return m_client_area_height;
+ /**
+ * Gets window client area width in logical coordinates.
+ * @note For high-DPI systems, this is smaller than the framebuffer size.
+ * @note This method is thread-safe
+ */
+ std::pair<unsigned,unsigned> GetClientAreaSize() const {
+ return std::make_pair(client_area_width, client_area_height);
}
- void SetClientAreaHeight(const int val) {
- m_client_area_height = val;
+protected:
+ EmuWindow()
+ {
+ // TODO: Find a better place to set this.
+ config.min_client_area_size = std::make_pair(400u, 480u);
+ active_config = config;
}
+ virtual ~EmuWindow() {}
- std::string GetWindowTitle() const {
- return m_window_title;
+ /**
+ * Processes any pending configuration changes from the last SetConfig call.
+ * This method invokes OnMinimalClientAreaChangeRequest if the corresponding configuration
+ * field changed.
+ * @note Implementations will usually want to call this from the GUI thread.
+ * @todo Actually call this in existing implementations.
+ */
+ void ProcessConfigurationChanges() {
+ // TODO: For proper thread safety, we should eventually implement a proper
+ // multiple-writer/single-reader queue...
+
+ if (config.min_client_area_size != active_config.min_client_area_size) {
+ OnMinimalClientAreaChangeRequest(config.min_client_area_size);
+ config.min_client_area_size = active_config.min_client_area_size;
+ }
}
-
- void SetWindowTitle(std::string val) {
- m_window_title = val;
+
+ /**
+ * Update internal framebuffer size with the given parameter.
+ * @note EmuWindow implementations will usually use this in window resize event handlers.
+ */
+ void NotifyFramebufferSizeChanged(const std::pair<unsigned,unsigned>& size) {
+ framebuffer_size = size;
}
-protected:
- EmuWindow():
- m_client_area_width(640),
- m_client_area_height(480),
- m_window_title(Common::StringFromFormat("Citra | %s-%s", Common::g_scm_branch, Common::g_scm_desc))
- {}
- virtual ~EmuWindow() {}
+ /**
+ * Update internal client area size with the given parameter.
+ * @note EmuWindow implementations will usually use this in window resize event handlers.
+ */
+ void NotifyClientAreaSizeChanged(const std::pair<unsigned,unsigned>& size) {
+ client_area_width = size.first;
+ client_area_height = size.second;
+ }
- std::string m_window_title; ///< Current window title, should be used by window impl.
+private:
+ /**
+ * Handler called when the minimal client area was requested to be changed via SetConfig.
+ * For the request to be honored, EmuWindow implementations will usually reimplement this function.
+ */
+ virtual void OnMinimalClientAreaChangeRequest(const std::pair<unsigned,unsigned>& minimal_size) {
+ // By default, ignore this request and do nothing.
+ }
- int m_client_area_width; ///< Current client width, should be set by window impl.
- int m_client_area_height; ///< Current client height, should be set by window impl.
+ std::pair<unsigned,unsigned> framebuffer_size;
-private:
- WindowConfig m_config; ///< Internal configuration
+ unsigned client_area_width; ///< Current client width, should be set by window impl.
+ unsigned client_area_height; ///< Current client height, should be set by window impl.
+ WindowConfig config; ///< Internal configuration (changes pending for being applied in ProcessConfigurationChanges)
+ WindowConfig active_config; ///< Internal active configuration
};
diff --git a/src/common/extended_trace.cpp b/src/common/extended_trace.cpp
index 9cd0398ed..cf7c346d4 100644
--- a/src/common/extended_trace.cpp
+++ b/src/common/extended_trace.cpp
@@ -29,7 +29,7 @@ using namespace std;
void PCSTR2LPTSTR( PCSTR lpszIn, LPTSTR lpszOut )
{
#if defined(UNICODE)||defined(_UNICODE)
- ULONG index = 0;
+ ULONG index = 0;
PCSTR lpAct = lpszIn;
for( ; ; lpAct++ )
@@ -37,7 +37,7 @@ void PCSTR2LPTSTR( PCSTR lpszIn, LPTSTR lpszOut )
lpszOut[index++] = (TCHAR)(*lpAct);
if ( *lpAct == 0 )
break;
- }
+ }
#else
// This is trivial :)
strcpy( lpszOut, lpszIn );
@@ -82,7 +82,7 @@ static void InitSymbolPath( PSTR lpszSymbolPath, PCSTR lpszIniPath )
}
// Add user defined path
- if ( lpszIniPath != NULL )
+ if ( lpszIniPath != nullptr )
if ( lpszIniPath[0] != '\0' )
{
strcat( lpszSymbolPath, ";" );
@@ -101,7 +101,7 @@ BOOL InitSymInfo( PCSTR lpszInitialSymbolPath )
CHAR lpszSymbolPath[BUFFERSIZE];
DWORD symOptions = SymGetOptions();
- symOptions |= SYMOPT_LOAD_LINES;
+ symOptions |= SYMOPT_LOAD_LINES;
symOptions &= ~SYMOPT_UNDNAME;
SymSetOptions( symOptions );
InitSymbolPath( lpszSymbolPath, lpszInitialSymbolPath );
@@ -138,7 +138,7 @@ static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, L
DWORD dwSymSize = 10000;
TCHAR lpszUnDSymbol[BUFFERSIZE]=_T("?");
CHAR lpszNonUnicodeUnDSymbol[BUFFERSIZE]="?";
- LPTSTR lpszParamSep = NULL;
+ LPTSTR lpszParamSep = nullptr;
LPTSTR lpszParsed = lpszUnDSymbol;
PIMAGEHLP_SYMBOL pSym = (PIMAGEHLP_SYMBOL)GlobalAlloc( GMEM_FIXED, dwSymSize );
@@ -153,15 +153,15 @@ static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, L
#ifndef _M_X64
DWORD dwDisp = 0;
if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, &dwDisp, pSym ) )
-#else
+#else
//makes it compile but hell im not sure if this works...
DWORD64 dwDisp = 0;
if ( SymGetSymFromAddr( GetCurrentProcess(), (ULONG)fnAddress, (PDWORD64)&dwDisp, pSym ) )
#endif
{
// Make the symbol readable for humans
- UnDecorateSymbolName( pSym->Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE,
- UNDNAME_COMPLETE |
+ UnDecorateSymbolName( pSym->Name, lpszNonUnicodeUnDSymbol, BUFFERSIZE,
+ UNDNAME_COMPLETE |
UNDNAME_NO_THISTYPE |
UNDNAME_NO_SPECIAL_SYMS |
UNDNAME_NO_MEMBER_TYPE |
@@ -187,13 +187,13 @@ static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, L
// Let's go through the stack, and modify the function prototype, and insert the actual
// parameter values from the stack
- if ( _tcsstr( lpszUnDSymbol, _T("(void)") ) == NULL && _tcsstr( lpszUnDSymbol, _T("()") ) == NULL)
+ if ( _tcsstr( lpszUnDSymbol, _T("(void)") ) == nullptr && _tcsstr( lpszUnDSymbol, _T("()") ) == nullptr)
{
ULONG index = 0;
for( ; ; index++ )
{
lpszParamSep = _tcschr( lpszParsed, _T(',') );
- if ( lpszParamSep == NULL )
+ if ( lpszParamSep == nullptr )
break;
*lpszParamSep = _T('\0');
@@ -205,7 +205,7 @@ static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, L
}
lpszParamSep = _tcschr( lpszParsed, _T(')') );
- if ( lpszParamSep != NULL )
+ if ( lpszParamSep != nullptr )
{
*lpszParamSep = _T('\0');
@@ -219,7 +219,7 @@ static BOOL GetFunctionInfoFromAddresses( ULONG fnAddress, ULONG stackAddress, L
_tcscat( lpszSymbol, lpszParsed );
ret = TRUE;
- }
+ }
GlobalFree( pSym );
return ret;
@@ -248,7 +248,7 @@ static BOOL GetSourceInfoFromAddress( UINT address, LPTSTR lpszSourceInfo )
PCSTR2LPTSTR( lineInfo.FileName, lpszFileName );
TCHAR fname[_MAX_FNAME];
TCHAR ext[_MAX_EXT];
- _tsplitpath(lpszFileName, NULL, NULL, fname, ext);
+ _tsplitpath(lpszFileName, nullptr, nullptr, fname, ext);
_stprintf( lpszSourceInfo, _T("%s%s(%d)"), fname, ext, lineInfo.LineNumber );
ret = TRUE;
}
@@ -325,23 +325,23 @@ void StackTrace( HANDLE hThread, const char* lpszMessage, FILE *file )
PrintFunctionAndSourceInfo(file, callStack);
- for( ULONG index = 0; ; index++ )
+ for( ULONG index = 0; ; index++ )
{
bResult = StackWalk(
IMAGE_FILE_MACHINE_I386,
hProcess,
hThread,
&callStack,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
SymFunctionTableAccess,
SymGetModuleBase,
- NULL);
+ nullptr);
if ( index == 0 )
continue;
- if( !bResult || callStack.AddrFrame.Offset == 0 )
+ if( !bResult || callStack.AddrFrame.Offset == 0 )
break;
PrintFunctionAndSourceInfo(file, callStack);
@@ -382,23 +382,23 @@ void StackTrace(HANDLE hThread, const char* lpszMessage, FILE *file, DWORD eip,
PrintFunctionAndSourceInfo(file, callStack);
- for( ULONG index = 0; ; index++ )
+ for( ULONG index = 0; ; index++ )
{
bResult = StackWalk(
IMAGE_FILE_MACHINE_I386,
hProcess,
hThread,
&callStack,
- NULL,
- NULL,
+ nullptr,
+ nullptr,
SymFunctionTableAccess,
SymGetModuleBase,
- NULL);
+ nullptr);
if ( index == 0 )
continue;
- if( !bResult || callStack.AddrFrame.Offset == 0 )
+ if( !bResult || callStack.AddrFrame.Offset == 0 )
break;
PrintFunctionAndSourceInfo(file, callStack);
diff --git a/src/common/fifo_queue.h b/src/common/fifo_queue.h
index 78a8f561d..b426e6596 100644
--- a/src/common/fifo_queue.h
+++ b/src/common/fifo_queue.h
@@ -45,7 +45,7 @@ public:
// create the element, add it to the queue
m_write_ptr->current = new T(std::forward<Arg>(t));
// set the next pointer to a new element ptr
- // then advance the write pointer
+ // then advance the write pointer
m_write_ptr = m_write_ptr->next = new ElementPtr();
Common::AtomicIncrement(m_size);
}
@@ -57,7 +57,7 @@ public:
// advance the read pointer
m_read_ptr = m_read_ptr->next;
// set the next element to NULL to stop the recursive deletion
- tmpptr->next = NULL;
+ tmpptr->next = nullptr;
delete tmpptr; // this also deletes the element
}
@@ -86,7 +86,7 @@ private:
class ElementPtr
{
public:
- ElementPtr() : current(NULL), next(NULL) {}
+ ElementPtr() : current(nullptr), next(nullptr) {}
~ElementPtr()
{
diff --git a/src/common/file_search.cpp b/src/common/file_search.cpp
index 63580f688..bfb54ce72 100644
--- a/src/common/file_search.cpp
+++ b/src/common/file_search.cpp
@@ -43,7 +43,7 @@ void CFileSearch::FindFiles(const std::string& _searchString, const std::string&
bool bkeepLooping = true;
while (bkeepLooping)
- {
+ {
if (findData.cFileName[0] != '.')
{
std::string strFilename;
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 35da07306..42cdf3262 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -88,7 +88,7 @@ bool IsDirectory(const std::string &filename)
#endif
if (result < 0) {
- WARN_LOG(COMMON, "IsDirectory: stat failed on %s: %s",
+ LOG_WARNING(Common_Filesystem, "stat failed on %s: %s",
filename.c_str(), GetLastErrorMsg());
return false;
}
@@ -100,33 +100,33 @@ bool IsDirectory(const std::string &filename)
// Doesn't supports deleting a directory
bool Delete(const std::string &filename)
{
- INFO_LOG(COMMON, "Delete: file %s", filename.c_str());
+ LOG_INFO(Common_Filesystem, "file %s", filename.c_str());
- // Return true because we care about the file no
+ // Return true because we care about the file no
// being there, not the actual delete.
if (!Exists(filename))
{
- WARN_LOG(COMMON, "Delete: %s does not exist", filename.c_str());
+ LOG_WARNING(Common_Filesystem, "%s does not exist", filename.c_str());
return true;
}
// We can't delete a directory
if (IsDirectory(filename))
{
- WARN_LOG(COMMON, "Delete failed: %s is a directory", filename.c_str());
+ LOG_ERROR(Common_Filesystem, "Failed: %s is a directory", filename.c_str());
return false;
}
#ifdef _WIN32
if (!DeleteFile(Common::UTF8ToTStr(filename).c_str()))
{
- WARN_LOG(COMMON, "Delete: DeleteFile failed on %s: %s",
+ LOG_ERROR(Common_Filesystem, "DeleteFile failed on %s: %s",
filename.c_str(), GetLastErrorMsg());
return false;
}
#else
if (unlink(filename.c_str()) == -1) {
- WARN_LOG(COMMON, "Delete: unlink failed on %s: %s",
+ LOG_ERROR(Common_Filesystem, "unlink failed on %s: %s",
filename.c_str(), GetLastErrorMsg());
return false;
}
@@ -138,17 +138,17 @@ bool Delete(const std::string &filename)
// Returns true if successful, or path already exists.
bool CreateDir(const std::string &path)
{
- INFO_LOG(COMMON, "CreateDir: directory %s", path.c_str());
+ LOG_TRACE(Common_Filesystem, "directory %s", path.c_str());
#ifdef _WIN32
- if (::CreateDirectory(Common::UTF8ToTStr(path).c_str(), NULL))
+ if (::CreateDirectory(Common::UTF8ToTStr(path).c_str(), nullptr))
return true;
DWORD error = GetLastError();
if (error == ERROR_ALREADY_EXISTS)
{
- WARN_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: already exists", path.c_str());
+ LOG_WARNING(Common_Filesystem, "CreateDirectory failed on %s: already exists", path.c_str());
return true;
}
- ERROR_LOG(COMMON, "CreateDir: CreateDirectory failed on %s: %i", path.c_str(), error);
+ LOG_ERROR(Common_Filesystem, "CreateDirectory failed on %s: %i", path.c_str(), error);
return false;
#else
if (mkdir(path.c_str(), 0755) == 0)
@@ -158,11 +158,11 @@ bool CreateDir(const std::string &path)
if (err == EEXIST)
{
- WARN_LOG(COMMON, "CreateDir: mkdir failed on %s: already exists", path.c_str());
+ LOG_WARNING(Common_Filesystem, "mkdir failed on %s: already exists", path.c_str());
return true;
}
- ERROR_LOG(COMMON, "CreateDir: mkdir failed on %s: %s", path.c_str(), strerror(err));
+ LOG_ERROR(Common_Filesystem, "mkdir failed on %s: %s", path.c_str(), strerror(err));
return false;
#endif
}
@@ -171,11 +171,11 @@ bool CreateDir(const std::string &path)
bool CreateFullPath(const std::string &fullPath)
{
int panicCounter = 100;
- INFO_LOG(COMMON, "CreateFullPath: path %s", fullPath.c_str());
+ LOG_TRACE(Common_Filesystem, "path %s", fullPath.c_str());
if (FileUtil::Exists(fullPath))
{
- INFO_LOG(COMMON, "CreateFullPath: path exists %s", fullPath.c_str());
+ LOG_WARNING(Common_Filesystem, "path exists %s", fullPath.c_str());
return true;
}
@@ -192,7 +192,7 @@ bool CreateFullPath(const std::string &fullPath)
// Include the '/' so the first call is CreateDir("/") rather than CreateDir("")
std::string const subPath(fullPath.substr(0, position + 1));
if (!FileUtil::IsDirectory(subPath) && !FileUtil::CreateDir(subPath)) {
- ERROR_LOG(COMMON, "CreateFullPath: directory creation failed");
+ LOG_ERROR(Common, "CreateFullPath: directory creation failed");
return false;
}
@@ -200,7 +200,7 @@ bool CreateFullPath(const std::string &fullPath)
panicCounter--;
if (panicCounter <= 0)
{
- ERROR_LOG(COMMON, "CreateFullPath: directory structure is too deep");
+ LOG_ERROR(Common, "CreateFullPath: directory structure is too deep");
return false;
}
position++;
@@ -211,12 +211,12 @@ bool CreateFullPath(const std::string &fullPath)
// Deletes a directory filename, returns true on success
bool DeleteDir(const std::string &filename)
{
- INFO_LOG(COMMON, "DeleteDir: directory %s", filename.c_str());
+ LOG_INFO(Common_Filesystem, "directory %s", filename.c_str());
// check if a directory
if (!FileUtil::IsDirectory(filename))
{
- ERROR_LOG(COMMON, "DeleteDir: Not a directory %s", filename.c_str());
+ LOG_ERROR(Common_Filesystem, "Not a directory %s", filename.c_str());
return false;
}
@@ -227,33 +227,33 @@ bool DeleteDir(const std::string &filename)
if (rmdir(filename.c_str()) == 0)
return true;
#endif
- ERROR_LOG(COMMON, "DeleteDir: %s: %s", filename.c_str(), GetLastErrorMsg());
+ LOG_ERROR(Common_Filesystem, "failed %s: %s", filename.c_str(), GetLastErrorMsg());
return false;
}
-// renames file srcFilename to destFilename, returns true on success
+// renames file srcFilename to destFilename, returns true on success
bool Rename(const std::string &srcFilename, const std::string &destFilename)
{
- INFO_LOG(COMMON, "Rename: %s --> %s",
+ LOG_TRACE(Common_Filesystem, "%s --> %s",
srcFilename.c_str(), destFilename.c_str());
if (rename(srcFilename.c_str(), destFilename.c_str()) == 0)
return true;
- ERROR_LOG(COMMON, "Rename: failed %s --> %s: %s",
+ LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s",
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
return false;
}
-// copies file srcFilename to destFilename, returns true on success
+// copies file srcFilename to destFilename, returns true on success
bool Copy(const std::string &srcFilename, const std::string &destFilename)
{
- INFO_LOG(COMMON, "Copy: %s --> %s",
+ LOG_TRACE(Common_Filesystem, "%s --> %s",
srcFilename.c_str(), destFilename.c_str());
#ifdef _WIN32
if (CopyFile(Common::UTF8ToTStr(srcFilename).c_str(), Common::UTF8ToTStr(destFilename).c_str(), FALSE))
return true;
- ERROR_LOG(COMMON, "Copy: failed %s --> %s: %s",
+ LOG_ERROR(Common_Filesystem, "failed %s --> %s: %s",
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
return false;
#else
@@ -267,7 +267,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
FILE *input = fopen(srcFilename.c_str(), "rb");
if (!input)
{
- ERROR_LOG(COMMON, "Copy: input failed %s --> %s: %s",
+ LOG_ERROR(Common_Filesystem, "opening input failed %s --> %s: %s",
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
return false;
}
@@ -277,7 +277,7 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
if (!output)
{
fclose(input);
- ERROR_LOG(COMMON, "Copy: output failed %s --> %s: %s",
+ LOG_ERROR(Common_Filesystem, "opening output failed %s --> %s: %s",
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
return false;
}
@@ -291,8 +291,8 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
{
if (ferror(input) != 0)
{
- ERROR_LOG(COMMON,
- "Copy: failed reading from source, %s --> %s: %s",
+ LOG_ERROR(Common_Filesystem,
+ "failed reading from source, %s --> %s: %s",
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
goto bail;
}
@@ -302,8 +302,8 @@ bool Copy(const std::string &srcFilename, const std::string &destFilename)
int wnum = fwrite(buffer, sizeof(char), rnum, output);
if (wnum != rnum)
{
- ERROR_LOG(COMMON,
- "Copy: failed writing to output, %s --> %s: %s",
+ LOG_ERROR(Common_Filesystem,
+ "failed writing to output, %s --> %s: %s",
srcFilename.c_str(), destFilename.c_str(), GetLastErrorMsg());
goto bail;
}
@@ -326,16 +326,16 @@ u64 GetSize(const std::string &filename)
{
if (!Exists(filename))
{
- WARN_LOG(COMMON, "GetSize: failed %s: No such file", filename.c_str());
+ LOG_ERROR(Common_Filesystem, "failed %s: No such file", filename.c_str());
return 0;
}
if (IsDirectory(filename))
{
- WARN_LOG(COMMON, "GetSize: failed %s: is a directory", filename.c_str());
+ LOG_ERROR(Common_Filesystem, "failed %s: is a directory", filename.c_str());
return 0;
}
-
+
struct stat64 buf;
#ifdef _WIN32
if (_tstat64(Common::UTF8ToTStr(filename).c_str(), &buf) == 0)
@@ -343,12 +343,12 @@ u64 GetSize(const std::string &filename)
if (stat64(filename.c_str(), &buf) == 0)
#endif
{
- DEBUG_LOG(COMMON, "GetSize: %s: %lld",
+ LOG_TRACE(Common_Filesystem, "%s: %lld",
filename.c_str(), (long long)buf.st_size);
return buf.st_size;
}
- ERROR_LOG(COMMON, "GetSize: Stat failed %s: %s",
+ LOG_ERROR(Common_Filesystem, "Stat failed %s: %s",
filename.c_str(), GetLastErrorMsg());
return 0;
}
@@ -358,7 +358,7 @@ u64 GetSize(const int fd)
{
struct stat64 buf;
if (fstat64(fd, &buf) != 0) {
- ERROR_LOG(COMMON, "GetSize: stat failed %i: %s",
+ LOG_ERROR(Common_Filesystem, "GetSize: stat failed %i: %s",
fd, GetLastErrorMsg());
return 0;
}
@@ -371,27 +371,27 @@ u64 GetSize(FILE *f)
// can't use off_t here because it can be 32-bit
u64 pos = ftello(f);
if (fseeko(f, 0, SEEK_END) != 0) {
- ERROR_LOG(COMMON, "GetSize: seek failed %p: %s",
+ LOG_ERROR(Common_Filesystem, "GetSize: seek failed %p: %s",
f, GetLastErrorMsg());
return 0;
}
u64 size = ftello(f);
if ((size != pos) && (fseeko(f, pos, SEEK_SET) != 0)) {
- ERROR_LOG(COMMON, "GetSize: seek failed %p: %s",
+ LOG_ERROR(Common_Filesystem, "GetSize: seek failed %p: %s",
f, GetLastErrorMsg());
return 0;
}
return size;
}
-// creates an empty file filename, returns true on success
+// creates an empty file filename, returns true on success
bool CreateEmptyFile(const std::string &filename)
{
- INFO_LOG(COMMON, "CreateEmptyFile: %s", filename.c_str());
+ LOG_TRACE(Common_Filesystem, "%s", filename.c_str());
if (!FileUtil::IOFile(filename, "wb"))
{
- ERROR_LOG(COMMON, "CreateEmptyFile: failed %s: %s",
+ LOG_ERROR(Common_Filesystem, "failed %s: %s",
filename.c_str(), GetLastErrorMsg());
return false;
}
@@ -404,7 +404,7 @@ bool CreateEmptyFile(const std::string &filename)
// results into parentEntry. Returns the number of files+directories found
u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
{
- INFO_LOG(COMMON, "ScanDirectoryTree: directory %s", directory.c_str());
+ LOG_TRACE(Common_Filesystem, "directory %s", directory.c_str());
// How many files + directories we found
u32 foundEntries = 0;
#ifdef _WIN32
@@ -423,7 +423,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
FSTEntry entry;
const std::string virtualName(Common::TStrToUTF8(ffd.cFileName));
#else
- struct dirent dirent, *result = NULL;
+ struct dirent dirent, *result = nullptr;
DIR *dirp = opendir(directory.c_str());
if (!dirp)
@@ -437,7 +437,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
#endif
// check for "." and ".."
if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
- ((virtualName[0] == '.') && (virtualName[1] == '.') &&
+ ((virtualName[0] == '.') && (virtualName[1] == '.') &&
(virtualName[2] == '\0')))
continue;
entry.virtualName = virtualName;
@@ -452,14 +452,14 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
foundEntries += (u32)entry.size;
}
else
- { // is a file
+ { // is a file
entry.isDirectory = false;
entry.size = GetSize(entry.physicalName.c_str());
}
++foundEntries;
// Push into the tree
- parentEntry.children.push_back(entry);
-#ifdef _WIN32
+ parentEntry.children.push_back(entry);
+#ifdef _WIN32
} while (FindNextFile(hFind, &ffd) != 0);
FindClose(hFind);
#else
@@ -474,7 +474,7 @@ u32 ScanDirectoryTree(const std::string &directory, FSTEntry& parentEntry)
// Deletes the given directory and anything under it. Returns true on success.
bool DeleteDirRecursively(const std::string &directory)
{
- INFO_LOG(COMMON, "DeleteDirRecursively: %s", directory.c_str());
+ LOG_TRACE(Common_Filesystem, "%s", directory.c_str());
#ifdef _WIN32
// Find the first file in the directory.
WIN32_FIND_DATA ffd;
@@ -491,7 +491,7 @@ bool DeleteDirRecursively(const std::string &directory)
{
const std::string virtualName(Common::TStrToUTF8(ffd.cFileName));
#else
- struct dirent dirent, *result = NULL;
+ struct dirent dirent, *result = nullptr;
DIR *dirp = opendir(directory.c_str());
if (!dirp)
return false;
@@ -504,7 +504,7 @@ bool DeleteDirRecursively(const std::string &directory)
// check for "." and ".."
if (((virtualName[0] == '.') && (virtualName[1] == '\0')) ||
- ((virtualName[0] == '.') && (virtualName[1] == '.') &&
+ ((virtualName[0] == '.') && (virtualName[1] == '.') &&
(virtualName[2] == '\0')))
continue;
@@ -540,7 +540,7 @@ bool DeleteDirRecursively(const std::string &directory)
closedir(dirp);
#endif
FileUtil::DeleteDir(directory);
-
+
return true;
}
@@ -552,7 +552,7 @@ void CopyDir(const std::string &source_path, const std::string &dest_path)
if (!FileUtil::Exists(source_path)) return;
if (!FileUtil::Exists(dest_path)) FileUtil::CreateFullPath(dest_path);
- struct dirent dirent, *result = NULL;
+ struct dirent dirent, *result = nullptr;
DIR *dirp = opendir(source_path.c_str());
if (!dirp) return;
@@ -585,12 +585,12 @@ void CopyDir(const std::string &source_path, const std::string &dest_path)
std::string GetCurrentDir()
{
char *dir;
- // Get the current working directory (getcwd uses malloc)
- if (!(dir = __getcwd(NULL, 0))) {
+ // Get the current working directory (getcwd uses malloc)
+ if (!(dir = __getcwd(nullptr, 0))) {
- ERROR_LOG(COMMON, "GetCurrentDirectory failed: %s",
+ LOG_ERROR(Common_Filesystem, "GetCurrentDirectory failed: %s",
GetLastErrorMsg());
- return NULL;
+ return nullptr;
}
std::string strDir = dir;
free(dir);
@@ -604,7 +604,7 @@ bool SetCurrentDir(const std::string &directory)
}
#if defined(__APPLE__)
-std::string GetBundleDirectory()
+std::string GetBundleDirectory()
{
CFURLRef BundleRef;
char AppBundlePath[MAXPATHLEN];
@@ -626,7 +626,7 @@ std::string& GetExeDirectory()
if (DolphinPath.empty())
{
TCHAR Dolphin_exe_Path[2048];
- GetModuleFileName(NULL, Dolphin_exe_Path, 2048);
+ GetModuleFileName(nullptr, Dolphin_exe_Path, 2048);
DolphinPath = Common::TStrToUTF8(Dolphin_exe_Path);
DolphinPath = DolphinPath.substr(0, DolphinPath.find_last_of('\\'));
}
@@ -647,7 +647,7 @@ std::string GetSysDirectory()
#endif
sysDir += DIR_SEP;
- INFO_LOG(COMMON, "GetSysDirectory: Setting to %s:", sysDir.c_str());
+ LOG_DEBUG(Common_Filesystem, "Setting to %s:", sysDir.c_str());
return sysDir;
}
@@ -666,8 +666,8 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
if (FileUtil::Exists(ROOT_DIR DIR_SEP USERDATA_DIR))
paths[D_USER_IDX] = ROOT_DIR DIR_SEP USERDATA_DIR DIR_SEP;
else
- paths[D_USER_IDX] = std::string(getenv("HOME") ?
- getenv("HOME") : getenv("PWD") ?
+ paths[D_USER_IDX] = std::string(getenv("HOME") ?
+ getenv("HOME") : getenv("PWD") ?
getenv("PWD") : "") + DIR_SEP EMU_DATA_DIR DIR_SEP;
#endif
@@ -676,6 +676,8 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
+ paths[D_SAVEDATA_IDX] = paths[D_USER_IDX] + SAVEDATA_DIR DIR_SEP;
+ paths[D_SYSDATA_IDX] = paths[D_USER_IDX] + SYSDATA_DIR DIR_SEP;
paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
@@ -694,7 +696,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
{
if (!FileUtil::IsDirectory(newPath))
{
- WARN_LOG(COMMON, "Invalid path specified %s", newPath.c_str());
+ LOG_ERROR(Common_Filesystem, "Invalid path specified %s", newPath.c_str());
return paths[DirIDX];
}
else
@@ -717,6 +719,7 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
paths[D_MAPS_IDX] = paths[D_USER_IDX] + MAPS_DIR DIR_SEP;
paths[D_CACHE_IDX] = paths[D_USER_IDX] + CACHE_DIR DIR_SEP;
paths[D_SDMC_IDX] = paths[D_USER_IDX] + SDMC_DIR DIR_SEP;
+ paths[D_SAVEDATA_IDX] = paths[D_USER_IDX] + SAVEDATA_DIR DIR_SEP;
paths[D_SHADERCACHE_IDX] = paths[D_USER_IDX] + SHADERCACHE_DIR DIR_SEP;
paths[D_SHADERS_IDX] = paths[D_USER_IDX] + SHADERS_DIR DIR_SEP;
paths[D_STATESAVES_IDX] = paths[D_USER_IDX] + STATESAVES_DIR DIR_SEP;
@@ -749,23 +752,10 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new
paths[F_MAINLOG_IDX] = paths[D_LOGS_IDX] + MAIN_LOG;
}
}
-
+
return paths[DirIDX];
}
-//std::string GetThemeDir(const std::string& theme_name)
-//{
-// std::string dir = FileUtil::GetUserPath(D_THEMES_IDX) + theme_name + "/";
-//
-//#if !defined(_WIN32)
-// // If theme does not exist in user's dir load from shared directory
-// if (!FileUtil::Exists(dir))
-// dir = SHARED_USER_DIR THEMES_DIR "/" + theme_name + "/";
-//#endif
-//
-// return dir;
-//}
-
size_t WriteStringToFile(bool text_file, const std::string &str, const char *filename)
{
return FileUtil::IOFile(filename, text_file ? "w" : "wb").WriteBytes(str.data(), str.size());
@@ -826,7 +816,7 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
}
IOFile::IOFile()
- : m_file(NULL), m_good(true)
+ : m_file(nullptr), m_good(true)
{}
IOFile::IOFile(std::FILE* file)
@@ -834,7 +824,7 @@ IOFile::IOFile(std::FILE* file)
{}
IOFile::IOFile(const std::string& filename, const char openmode[])
- : m_file(NULL), m_good(true)
+ : m_file(nullptr), m_good(true)
{
Open(filename, openmode);
}
@@ -845,7 +835,7 @@ IOFile::~IOFile()
}
IOFile::IOFile(IOFile&& other)
- : m_file(NULL), m_good(true)
+ : m_file(nullptr), m_good(true)
{
Swap(other);
}
@@ -880,14 +870,14 @@ bool IOFile::Close()
if (!IsOpen() || 0 != std::fclose(m_file))
m_good = false;
- m_file = NULL;
+ m_file = nullptr;
return m_good;
}
std::FILE* IOFile::ReleaseHandle()
{
std::FILE* const ret = m_file;
- m_file = NULL;
+ m_file = nullptr;
return ret;
}
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 173ce6623..e691b6139 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -16,33 +16,35 @@
// User directory indices for GetUserPath
enum {
- D_USER_IDX,
- D_ROOT_IDX,
- D_CONFIG_IDX,
- D_GAMECONFIG_IDX,
- D_MAPS_IDX,
- D_CACHE_IDX,
- D_SHADERCACHE_IDX,
- D_SHADERS_IDX,
- D_STATESAVES_IDX,
- D_SCREENSHOTS_IDX,
- D_SDMC_IDX,
- D_HIRESTEXTURES_IDX,
- D_DUMP_IDX,
- D_DUMPFRAMES_IDX,
- D_DUMPAUDIO_IDX,
- D_DUMPTEXTURES_IDX,
- D_DUMPDSP_IDX,
- D_LOGS_IDX,
- D_SYSCONF_IDX,
- F_EMUCONFIG_IDX,
- F_DEBUGGERCONFIG_IDX,
- F_LOGGERCONFIG_IDX,
- F_MAINLOG_IDX,
- F_RAMDUMP_IDX,
- F_ARAMDUMP_IDX,
- F_SYSCONF_IDX,
- NUM_PATH_INDICES
+ D_USER_IDX,
+ D_ROOT_IDX,
+ D_CONFIG_IDX,
+ D_GAMECONFIG_IDX,
+ D_MAPS_IDX,
+ D_CACHE_IDX,
+ D_SHADERCACHE_IDX,
+ D_SHADERS_IDX,
+ D_STATESAVES_IDX,
+ D_SCREENSHOTS_IDX,
+ D_SDMC_IDX,
+ D_SAVEDATA_IDX,
+ D_SYSDATA_IDX,
+ D_HIRESTEXTURES_IDX,
+ D_DUMP_IDX,
+ D_DUMPFRAMES_IDX,
+ D_DUMPAUDIO_IDX,
+ D_DUMPTEXTURES_IDX,
+ D_DUMPDSP_IDX,
+ D_LOGS_IDX,
+ D_SYSCONF_IDX,
+ F_EMUCONFIG_IDX,
+ F_DEBUGGERCONFIG_IDX,
+ F_LOGGERCONFIG_IDX,
+ F_MAINLOG_IDX,
+ F_RAMDUMP_IDX,
+ F_ARAMDUMP_IDX,
+ F_SYSCONF_IDX,
+ NUM_PATH_INDICES
};
namespace FileUtil
@@ -51,11 +53,11 @@ namespace FileUtil
// FileSystem tree node/
struct FSTEntry
{
- bool isDirectory;
- u64 size; // file length or number of entries from children
- std::string physicalName; // name on disk
- std::string virtualName; // name in FST names table
- std::vector<FSTEntry> children;
+ bool isDirectory;
+ u64 size; // file length or number of entries from children
+ std::string physicalName; // name on disk
+ std::string virtualName; // name in FST names table
+ std::vector<FSTEntry> children;
};
// Returns true if file filename exists
@@ -148,86 +150,86 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
class IOFile : public NonCopyable
{
public:
- IOFile();
- IOFile(std::FILE* file);
- IOFile(const std::string& filename, const char openmode[]);
+ IOFile();
+ IOFile(std::FILE* file);
+ IOFile(const std::string& filename, const char openmode[]);
- ~IOFile();
+ ~IOFile();
- IOFile(IOFile&& other);
- IOFile& operator=(IOFile&& other);
+ IOFile(IOFile&& other);
+ IOFile& operator=(IOFile&& other);
- void Swap(IOFile& other);
+ void Swap(IOFile& other);
- bool Open(const std::string& filename, const char openmode[]);
- bool Close();
+ bool Open(const std::string& filename, const char openmode[]);
+ bool Close();
- template <typename T>
- size_t ReadArray(T* data, size_t length)
- {
- if (!IsOpen()) {
- m_good = false;
- return -1;
- }
+ template <typename T>
+ size_t ReadArray(T* data, size_t length)
+ {
+ if (!IsOpen()) {
+ m_good = false;
+ return -1;
+ }
- size_t items_read = std::fread(data, sizeof(T), length, m_file);
- if (items_read != length)
- m_good = false;
+ size_t items_read = std::fread(data, sizeof(T), length, m_file);
+ if (items_read != length)
+ m_good = false;
- return items_read;
- }
+ return items_read;
+ }
- template <typename T>
- size_t WriteArray(const T* data, size_t length)
- {
- if (!IsOpen()) {
- m_good = false;
- return -1;
- }
+ template <typename T>
+ size_t WriteArray(const T* data, size_t length)
+ {
+ if (!IsOpen()) {
+ m_good = false;
+ return -1;
+ }
- size_t items_written = std::fwrite(data, sizeof(T), length, m_file);
- if (items_written != length)
- m_good = false;
+ size_t items_written = std::fwrite(data, sizeof(T), length, m_file);
+ if (items_written != length)
+ m_good = false;
- return items_written;
- }
+ return items_written;
+ }
- size_t ReadBytes(void* data, size_t length)
- {
- return ReadArray(reinterpret_cast<char*>(data), length);
- }
+ size_t ReadBytes(void* data, size_t length)
+ {
+ return ReadArray(reinterpret_cast<char*>(data), length);
+ }
- size_t WriteBytes(const void* data, size_t length)
- {
- return WriteArray(reinterpret_cast<const char*>(data), length);
- }
+ size_t WriteBytes(const void* data, size_t length)
+ {
+ return WriteArray(reinterpret_cast<const char*>(data), length);
+ }
- bool IsOpen() { return NULL != m_file; }
+ bool IsOpen() { return nullptr != m_file; }
- // m_good is set to false when a read, write or other function fails
- bool IsGood() { return m_good; }
- operator void*() { return m_good ? m_file : NULL; }
+ // m_good is set to false when a read, write or other function fails
+ bool IsGood() { return m_good; }
+ operator void*() { return m_good ? m_file : nullptr; }
- std::FILE* ReleaseHandle();
+ std::FILE* ReleaseHandle();
- std::FILE* GetHandle() { return m_file; }
+ std::FILE* GetHandle() { return m_file; }
- void SetHandle(std::FILE* file);
+ void SetHandle(std::FILE* file);
- bool Seek(s64 off, int origin);
- u64 Tell();
- u64 GetSize();
- bool Resize(u64 size);
- bool Flush();
+ bool Seek(s64 off, int origin);
+ u64 Tell();
+ u64 GetSize();
+ bool Resize(u64 size);
+ bool Flush();
- // clear error state
- void Clear() { m_good = true; std::clearerr(m_file); }
+ // clear error state
+ void Clear() { m_good = true; std::clearerr(m_file); }
- std::FILE* m_file;
- bool m_good;
+ std::FILE* m_file;
+ bool m_good;
private:
- IOFile(IOFile&);
- IOFile& operator=(IOFile& other);
+ IOFile(IOFile&);
+ IOFile& operator=(IOFile& other);
};
} // namespace
@@ -237,8 +239,8 @@ template <typename T>
void OpenFStream(T& fstream, const std::string& filename, std::ios_base::openmode openmode)
{
#ifdef _WIN32
- fstream.open(Common::UTF8ToTStr(filename).c_str(), openmode);
+ fstream.open(Common::UTF8ToTStr(filename).c_str(), openmode);
#else
- fstream.open(filename.c_str(), openmode);
+ fstream.open(filename.c_str(), openmode);
#endif
}
diff --git a/src/common/hash.cpp b/src/common/hash.cpp
index d2ebc7341..2ddcfe6b7 100644
--- a/src/common/hash.cpp
+++ b/src/common/hash.cpp
@@ -115,15 +115,15 @@ inline u64 getblock(const u64 * p, int i)
inline void bmix64(u64 & h1, u64 & h2, u64 & k1, u64 & k2, u64 & c1, u64 & c2)
{
- k1 *= c1;
- k1 = _rotl64(k1,23);
+ k1 *= c1;
+ k1 = _rotl64(k1,23);
k1 *= c2;
h1 ^= k1;
h1 += h2;
h2 = _rotl64(h2,41);
- k2 *= c2;
+ k2 *= c2;
k2 = _rotl64(k2,23);
k2 *= c1;
h2 ^= k2;
@@ -250,7 +250,7 @@ u64 GetCRC32(const u8 *src, int len, u32 samples)
}
-/*
+/*
* NOTE: This hash function is used for custom texture loading/dumping, so
* it should not be changed, which would require all custom textures to be
* recalculated for their new hash values. If the hashing function is
@@ -273,7 +273,7 @@ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples)
u64 k = data[0];
data+=Step;
k *= m;
- k ^= k >> r;
+ k ^= k >> r;
k *= m;
h ^= k;
h *= m;
@@ -292,13 +292,13 @@ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples)
case 1: h ^= u64(data2[0]);
h *= m;
};
-
+
h ^= h >> r;
h *= m;
h ^= h >> r;
return h;
-}
+}
#else
// CRC32 hash using the SSE4.2 instruction
u64 GetCRC32(const u8 *src, int len, u32 samples)
@@ -351,15 +351,15 @@ inline u32 fmix32(u32 h)
inline void bmix32(u32 & h1, u32 & h2, u32 & k1, u32 & k2, u32 & c1, u32 & c2)
{
- k1 *= c1;
- k1 = _rotl(k1,11);
+ k1 *= c1;
+ k1 = _rotl(k1,11);
k1 *= c2;
h1 ^= k1;
h1 += h2;
h2 = _rotl(h2,17);
- k2 *= c2;
+ k2 *= c2;
k2 = _rotl(k2,11);
k2 *= c1;
h2 ^= k2;
@@ -405,7 +405,7 @@ u64 GetMurmurHash3(const u8* src, int len, u32 samples)
//----------
// tail
-
+
const u8 * tail = (const u8*)(data + nblocks*8);
u32 k1 = 0;
@@ -439,7 +439,7 @@ u64 GetMurmurHash3(const u8* src, int len, u32 samples)
out[0] = h1;
out[1] = h2;
-
+
return *((u64 *)&out);
}
@@ -463,11 +463,11 @@ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples)
{
u64 k = data[0];
data+=Step;
- k *= m;
- k ^= k >> r;
+ k *= m;
+ k ^= k >> r;
k *= m;
h ^= k;
- h *= m;
+ h *= m;
}
const u8 * data2 = (const u8*)end;
@@ -483,7 +483,7 @@ u64 GetHashHiresTexture(const u8 *src, int len, u32 samples)
case 1: h ^= u64(data2[0]);
h *= m;
};
-
+
h ^= h >> r;
h *= m;
h ^= h >> r;
diff --git a/src/common/linear_disk_cache.h b/src/common/linear_disk_cache.h
index 96dce3155..bb1b5174f 100644
--- a/src/common/linear_disk_cache.h
+++ b/src/common/linear_disk_cache.h
@@ -64,13 +64,13 @@ public:
m_file.seekg(0, std::ios::beg);
std::fstream::pos_type start_pos = m_file.tellg();
std::streamoff file_size = end_pos - start_pos;
-
+
if (m_file.is_open() && ValidateHeader())
{
// good header, read some key/value pairs
K key;
- V *value = NULL;
+ V *value = nullptr;
u32 value_size;
u32 entry_number;
@@ -87,7 +87,7 @@ public:
// read key/value and pass to reader
if (Read(&key) &&
- Read(value, value_size) &&
+ Read(value, value_size) &&
Read(&entry_number) &&
entry_number == m_num_entries+1)
{
@@ -115,7 +115,7 @@ public:
WriteHeader();
return 0;
}
-
+
void Sync()
{
m_file.flush();
diff --git a/src/common/log.h b/src/common/log.h
index bfd73f8a5..663eda9ad 100644
--- a/src/common/log.h
+++ b/src/common/log.h
@@ -4,104 +4,9 @@
#pragma once
-#ifndef LOGGING
-#define LOGGING
-#endif
-
-enum {
- OS_LEVEL, // Printed by the emulated operating system
- NOTICE_LEVEL, // VERY important information that is NOT errors. Like startup and OSReports.
- ERROR_LEVEL, // Critical errors
- WARNING_LEVEL, // Something is suspicious.
- INFO_LEVEL, // General information.
- DEBUG_LEVEL, // Detailed debugging - might make things slow.
-};
-
-namespace LogTypes
-{
-
-enum LOG_TYPE {
- ACTIONREPLAY,
- AUDIO,
- AUDIO_INTERFACE,
- BOOT,
- COMMANDPROCESSOR,
- COMMON,
- CONSOLE,
- CONFIG,
- DISCIO,
- FILEMON,
- DSPHLE,
- DSPLLE,
- DSP_MAIL,
- DSPINTERFACE,
- DVDINTERFACE,
- DYNA_REC,
- EXPANSIONINTERFACE,
- GDB_STUB,
- ARM11,
- GSP,
- OSHLE,
- MASTER_LOG,
- MEMMAP,
- MEMCARD_MANAGER,
- OSREPORT,
- PAD,
- PROCESSORINTERFACE,
- PIXELENGINE,
- SERIALINTERFACE,
- SP1,
- STREAMINGINTERFACE,
- VIDEO,
- VIDEOINTERFACE,
- LOADER,
- FILESYS,
- WII_IPC_DVD,
- WII_IPC_ES,
- WII_IPC_FILEIO,
- WII_IPC_HID,
- KERNEL,
- SVC,
- NDMA,
- HLE,
- RENDER,
- GPU,
- HW,
- TIME,
- NETPLAY,
-
- NUMBER_OF_LOGS // Must be last
-};
-
-// FIXME: should this be removed?
-enum LOG_LEVELS {
- LOS = OS_LEVEL,
- LNOTICE = NOTICE_LEVEL,
- LERROR = ERROR_LEVEL,
- LWARNING = WARNING_LEVEL,
- LINFO = INFO_LEVEL,
- LDEBUG = DEBUG_LEVEL,
-};
-
-#define LOGTYPES_LEVELS LogTypes::LOG_LEVELS
-#define LOGTYPES_TYPE LogTypes::LOG_TYPE
-
-} // namespace
-
-void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, const char*file, int line,
- const char* function, const char* fmt, ...)
-#ifdef __GNUC__
- __attribute__((format(printf, 6, 7)))
-#endif
- ;
-
-#if defined LOGGING || defined _DEBUG || defined DEBUGFAST
-#define MAX_LOGLEVEL LDEBUG
-#else
-#ifndef MAX_LOGLEVEL
-#define MAX_LOGLEVEL LWARNING
-#endif // loglevel
-#endif // logging
+#include "common/common_funcs.h"
+#include "common/msg_handler.h"
+#include "common/logging/log.h"
#ifdef _WIN32
#ifndef __func__
@@ -109,29 +14,16 @@ void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, const char*file, int
#endif
#endif
-// Let the compiler optimize this out
-#define GENERIC_LOG(t, v, ...) { \
- if (v <= LogTypes::MAX_LOGLEVEL) \
- GenericLog(v, t, __FILE__, __LINE__, __func__, __VA_ARGS__); \
- }
-
-#define OS_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LOS, __VA_ARGS__) } while (0)
-#define ERROR_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LERROR, __VA_ARGS__) } while (0)
-#define WARN_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LWARNING, __VA_ARGS__) } while (0)
-#define NOTICE_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LNOTICE, __VA_ARGS__) } while (0)
-#define INFO_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LINFO, __VA_ARGS__) } while (0)
-#define DEBUG_LOG(t,...) do { GENERIC_LOG(LogTypes::t, LogTypes::LDEBUG, __VA_ARGS__) } while (0)
-
-#if MAX_LOGLEVEL >= DEBUG_LEVEL
+#if _DEBUG
#define _dbg_assert_(_t_, _a_) \
if (!(_a_)) {\
- ERROR_LOG(_t_, "Error...\n\n Line: %d\n File: %s\n Time: %s\n\nIgnore and continue?", \
+ LOG_CRITICAL(_t_, "Error...\n\n Line: %d\n File: %s\n Time: %s\n\nIgnore and continue?", \
__LINE__, __FILE__, __TIME__); \
if (!PanicYesNo("*** Assertion (see log)***\n")) {Crash();} \
}
#define _dbg_assert_msg_(_t_, _a_, ...)\
if (!(_a_)) {\
- ERROR_LOG(_t_, __VA_ARGS__); \
+ LOG_CRITICAL(_t_, __VA_ARGS__); \
if (!PanicYesNo(__VA_ARGS__)) {Crash();} \
}
#define _dbg_update_() Host_UpdateLogDisplay();
@@ -143,11 +35,10 @@ void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, const char*file, int
#define _dbg_assert_(_t_, _a_) {}
#define _dbg_assert_msg_(_t_, _a_, _desc_, ...) {}
#endif // dbg_assert
-#endif // MAX_LOGLEVEL DEBUG
+#endif
#define _assert_(_a_) _dbg_assert_(MASTER_LOG, _a_)
-#ifndef GEKKO
#ifdef _WIN32
#define _assert_msg_(_t_, _a_, _fmt_, ...) \
if (!(_a_)) {\
@@ -159,6 +50,3 @@ void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, const char*file, int
if (!PanicYesNo(_fmt_, ##__VA_ARGS__)) {Crash();} \
}
#endif // WIN32
-#else // GEKKO
-#define _assert_msg_(_t_, _a_, _fmt_, ...)
-#endif
diff --git a/src/common/log_manager.cpp b/src/common/log_manager.cpp
deleted file mode 100644
index 4d590d98f..000000000
--- a/src/common/log_manager.cpp
+++ /dev/null
@@ -1,199 +0,0 @@
-// Copyright 2013 Dolphin Emulator Project
-// Licensed under GPLv2
-// Refer to the license.txt file included.
-
-#include <algorithm>
-
-#include "common/log_manager.h"
-#include "common/console_listener.h"
-#include "common/timer.h"
-#include "common/thread.h"
-
-void GenericLog(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line,
- const char* function, const char* fmt, ...)
-{
- va_list args;
- va_start(args, fmt);
-
- if (LogManager::GetInstance()) {
- LogManager::GetInstance()->Log(level, type,
- file, line, function, fmt, args);
- }
- va_end(args);
-}
-
-LogManager *LogManager::m_logManager = NULL;
-
-LogManager::LogManager()
-{
- // create log files
- m_Log[LogTypes::MASTER_LOG] = new LogContainer("*", "Master Log");
- m_Log[LogTypes::BOOT] = new LogContainer("BOOT", "Boot");
- m_Log[LogTypes::COMMON] = new LogContainer("COMMON", "Common");
- m_Log[LogTypes::CONFIG] = new LogContainer("CONFIG", "Configuration");
- m_Log[LogTypes::DISCIO] = new LogContainer("DIO", "Disc IO");
- m_Log[LogTypes::FILEMON] = new LogContainer("FileMon", "File Monitor");
- m_Log[LogTypes::PAD] = new LogContainer("PAD", "Pad");
- m_Log[LogTypes::PIXELENGINE] = new LogContainer("PE", "PixelEngine");
- m_Log[LogTypes::COMMANDPROCESSOR] = new LogContainer("CP", "CommandProc");
- m_Log[LogTypes::VIDEOINTERFACE] = new LogContainer("VI", "VideoInt");
- m_Log[LogTypes::SERIALINTERFACE] = new LogContainer("SI", "SerialInt");
- m_Log[LogTypes::PROCESSORINTERFACE] = new LogContainer("PI", "ProcessorInt");
- m_Log[LogTypes::MEMMAP] = new LogContainer("MI", "MI & memmap");
- m_Log[LogTypes::SP1] = new LogContainer("SP1", "Serial Port 1");
- m_Log[LogTypes::STREAMINGINTERFACE] = new LogContainer("Stream", "StreamingInt");
- m_Log[LogTypes::DSPINTERFACE] = new LogContainer("DSP", "DSPInterface");
- m_Log[LogTypes::DVDINTERFACE] = new LogContainer("DVD", "DVDInterface");
- m_Log[LogTypes::GSP] = new LogContainer("GSP", "GSP");
- m_Log[LogTypes::EXPANSIONINTERFACE] = new LogContainer("EXI", "ExpansionInt");
- m_Log[LogTypes::GDB_STUB] = new LogContainer("GDB_STUB", "GDB Stub");
- m_Log[LogTypes::AUDIO_INTERFACE] = new LogContainer("AI", "AudioInt");
- m_Log[LogTypes::ARM11] = new LogContainer("ARM11", "ARM11");
- m_Log[LogTypes::OSHLE] = new LogContainer("HLE", "HLE");
- m_Log[LogTypes::DSPHLE] = new LogContainer("DSPHLE", "DSP HLE");
- m_Log[LogTypes::DSPLLE] = new LogContainer("DSPLLE", "DSP LLE");
- m_Log[LogTypes::DSP_MAIL] = new LogContainer("DSPMails", "DSP Mails");
- m_Log[LogTypes::VIDEO] = new LogContainer("Video", "Video Backend");
- m_Log[LogTypes::AUDIO] = new LogContainer("Audio", "Audio Emulator");
- m_Log[LogTypes::DYNA_REC] = new LogContainer("JIT", "JIT");
- m_Log[LogTypes::CONSOLE] = new LogContainer("CONSOLE", "Dolphin Console");
- m_Log[LogTypes::OSREPORT] = new LogContainer("OSREPORT", "OSReport");
- m_Log[LogTypes::TIME] = new LogContainer("Time", "Core Timing");
- m_Log[LogTypes::LOADER] = new LogContainer("Loader", "Loader");
- m_Log[LogTypes::FILESYS] = new LogContainer("FileSys", "File System");
- m_Log[LogTypes::WII_IPC_HID] = new LogContainer("WII_IPC_HID", "WII IPC HID");
- m_Log[LogTypes::KERNEL] = new LogContainer("KERNEL", "KERNEL HLE");
- m_Log[LogTypes::WII_IPC_DVD] = new LogContainer("WII_IPC_DVD", "WII IPC DVD");
- m_Log[LogTypes::WII_IPC_ES] = new LogContainer("WII_IPC_ES", "WII IPC ES");
- m_Log[LogTypes::WII_IPC_FILEIO] = new LogContainer("WII_IPC_FILEIO", "WII IPC FILEIO");
- m_Log[LogTypes::RENDER] = new LogContainer("RENDER", "RENDER");
- m_Log[LogTypes::GPU] = new LogContainer("GPU", "GPU");
- m_Log[LogTypes::SVC] = new LogContainer("SVC", "Supervisor Call HLE");
- m_Log[LogTypes::NDMA] = new LogContainer("NDMA", "NDMA");
- m_Log[LogTypes::HLE] = new LogContainer("HLE", "High Level Emulation");
- m_Log[LogTypes::HW] = new LogContainer("HW", "Hardware");
- m_Log[LogTypes::ACTIONREPLAY] = new LogContainer("ActionReplay", "ActionReplay");
- m_Log[LogTypes::MEMCARD_MANAGER] = new LogContainer("MemCard Manager", "MemCard Manager");
- m_Log[LogTypes::NETPLAY] = new LogContainer("NETPLAY", "Netplay");
-
- m_fileLog = new FileLogListener(FileUtil::GetUserPath(F_MAINLOG_IDX).c_str());
- m_consoleLog = new ConsoleListener();
- m_debuggerLog = new DebuggerLogListener();
-
- for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
- {
- m_Log[i]->SetEnable(true);
- m_Log[i]->AddListener(m_fileLog);
- m_Log[i]->AddListener(m_consoleLog);
-#ifdef _MSC_VER
- if (IsDebuggerPresent())
- m_Log[i]->AddListener(m_debuggerLog);
-#endif
- }
-
- m_consoleLog->Open();
-}
-
-LogManager::~LogManager()
-{
- for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
- {
- m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_fileLog);
- m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_consoleLog);
- m_logManager->RemoveListener((LogTypes::LOG_TYPE)i, m_debuggerLog);
- }
-
- for (int i = 0; i < LogTypes::NUMBER_OF_LOGS; ++i)
- delete m_Log[i];
-
- delete m_fileLog;
- delete m_consoleLog;
- delete m_debuggerLog;
-}
-
-void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file,
- int line, const char* function, const char *fmt, va_list args)
-{
- char temp[MAX_MSGLEN];
- char msg[MAX_MSGLEN * 2];
- LogContainer *log = m_Log[type];
-
- if (!log->IsEnabled() || level > log->GetLevel() || ! log->HasListeners())
- return;
-
- Common::CharArrayFromFormatV(temp, MAX_MSGLEN, fmt, args);
-
- static const char level_to_char[7] = "ONEWID";
- sprintf(msg, "%s %s:%u %c[%s] %s: %s\n", Common::Timer::GetTimeFormatted().c_str(), file, line,
- level_to_char[(int)level], log->GetShortName(), function, temp);
-
-#ifdef ANDROID
- Host_SysMessage(msg);
-#endif
- log->Trigger(level, msg);
-}
-
-void LogManager::Init()
-{
- m_logManager = new LogManager();
-}
-
-void LogManager::Shutdown()
-{
- delete m_logManager;
- m_logManager = NULL;
-}
-
-LogContainer::LogContainer(const char* shortName, const char* fullName, bool enable)
- : m_enable(enable)
-{
- strncpy(m_fullName, fullName, 128);
- strncpy(m_shortName, shortName, 32);
- m_level = LogTypes::MAX_LOGLEVEL;
-}
-
-// LogContainer
-void LogContainer::AddListener(LogListener *listener)
-{
- std::lock_guard<std::mutex> lk(m_listeners_lock);
- m_listeners.insert(listener);
-}
-
-void LogContainer::RemoveListener(LogListener *listener)
-{
- std::lock_guard<std::mutex> lk(m_listeners_lock);
- m_listeners.erase(listener);
-}
-
-void LogContainer::Trigger(LogTypes::LOG_LEVELS level, const char *msg)
-{
- std::lock_guard<std::mutex> lk(m_listeners_lock);
-
- std::set<LogListener*>::const_iterator i;
- for (i = m_listeners.begin(); i != m_listeners.end(); ++i)
- {
- (*i)->Log(level, msg);
- }
-}
-
-FileLogListener::FileLogListener(const char *filename)
-{
- OpenFStream(m_logfile, filename, std::ios::app);
- SetEnable(true);
-}
-
-void FileLogListener::Log(LogTypes::LOG_LEVELS, const char *msg)
-{
- if (!IsEnabled() || !IsValid())
- return;
-
- std::lock_guard<std::mutex> lk(m_log_lock);
- m_logfile << msg << std::flush;
-}
-
-void DebuggerLogListener::Log(LogTypes::LOG_LEVELS, const char *msg)
-{
-#if _MSC_VER
- ::OutputDebugStringA(msg);
-#endif
-}
diff --git a/src/common/log_manager.h b/src/common/log_manager.h
deleted file mode 100644
index de1d16ee5..000000000
--- a/src/common/log_manager.h
+++ /dev/null
@@ -1,166 +0,0 @@
-// Copyright 2013 Dolphin Emulator Project
-// Licensed under GPLv2
-// Refer to the license.txt file included.
-
-#pragma once
-
-#include "common/log.h"
-#include "common/string_util.h"
-#include "common/file_util.h"
-
-#include <cstring>
-#include <set>
-#include <mutex>
-
-#define MAX_MESSAGES 8000
-#define MAX_MSGLEN 1024
-
-
-// pure virtual interface
-class LogListener
-{
-public:
- virtual ~LogListener() {}
-
- virtual void Log(LogTypes::LOG_LEVELS, const char *msg) = 0;
-};
-
-class FileLogListener : public LogListener
-{
-public:
- FileLogListener(const char *filename);
-
- void Log(LogTypes::LOG_LEVELS, const char *msg) override;
-
- bool IsValid() { return !m_logfile.fail(); }
- bool IsEnabled() const { return m_enable; }
- void SetEnable(bool enable) { m_enable = enable; }
-
- const char* GetName() const { return "file"; }
-
-private:
- std::mutex m_log_lock;
- std::ofstream m_logfile;
- bool m_enable;
-};
-
-class DebuggerLogListener : public LogListener
-{
-public:
- void Log(LogTypes::LOG_LEVELS, const char *msg) override;
-};
-
-class LogContainer
-{
-public:
- LogContainer(const char* shortName, const char* fullName, bool enable = false);
-
- const char* GetShortName() const { return m_shortName; }
- const char* GetFullName() const { return m_fullName; }
-
- void AddListener(LogListener* listener);
- void RemoveListener(LogListener* listener);
-
- void Trigger(LogTypes::LOG_LEVELS, const char *msg);
-
- bool IsEnabled() const { return m_enable; }
- void SetEnable(bool enable) { m_enable = enable; }
-
- LogTypes::LOG_LEVELS GetLevel() const { return m_level; }
-
- void SetLevel(LogTypes::LOG_LEVELS level) { m_level = level; }
-
- bool HasListeners() const { return !m_listeners.empty(); }
-
-private:
- char m_fullName[128];
- char m_shortName[32];
- bool m_enable;
- LogTypes::LOG_LEVELS m_level;
- std::mutex m_listeners_lock;
- std::set<LogListener*> m_listeners;
-};
-
-class ConsoleListener;
-
-class LogManager : NonCopyable
-{
-private:
- LogContainer* m_Log[LogTypes::NUMBER_OF_LOGS];
- FileLogListener *m_fileLog;
- ConsoleListener *m_consoleLog;
- DebuggerLogListener *m_debuggerLog;
- static LogManager *m_logManager; // Singleton. Ugh.
-
- LogManager();
- ~LogManager();
-public:
-
- static u32 GetMaxLevel() { return LogTypes::MAX_LOGLEVEL; }
-
- void Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const char* file, int line,
- const char* function, const char *fmt, va_list args);
-
- void SetLogLevel(LogTypes::LOG_TYPE type, LogTypes::LOG_LEVELS level)
- {
- m_Log[type]->SetLevel(level);
- }
-
- void SetEnable(LogTypes::LOG_TYPE type, bool enable)
- {
- m_Log[type]->SetEnable(enable);
- }
-
- bool IsEnabled(LogTypes::LOG_TYPE type) const
- {
- return m_Log[type]->IsEnabled();
- }
-
- const char* GetShortName(LogTypes::LOG_TYPE type) const
- {
- return m_Log[type]->GetShortName();
- }
-
- const char* GetFullName(LogTypes::LOG_TYPE type) const
- {
- return m_Log[type]->GetFullName();
- }
-
- void AddListener(LogTypes::LOG_TYPE type, LogListener *listener)
- {
- m_Log[type]->AddListener(listener);
- }
-
- void RemoveListener(LogTypes::LOG_TYPE type, LogListener *listener)
- {
- m_Log[type]->RemoveListener(listener);
- }
-
- FileLogListener *GetFileListener() const
- {
- return m_fileLog;
- }
-
- ConsoleListener *GetConsoleListener() const
- {
- return m_consoleLog;
- }
-
- DebuggerLogListener *GetDebuggerListener() const
- {
- return m_debuggerLog;
- }
-
- static LogManager* GetInstance()
- {
- return m_logManager;
- }
-
- static void SetInstance(LogManager *logManager)
- {
- m_logManager = logManager;
- }
-
- static void Init();
- static void Shutdown();
-};
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
new file mode 100644
index 000000000..e79b84604
--- /dev/null
+++ b/src/common/logging/backend.cpp
@@ -0,0 +1,151 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include <algorithm>
+
+#include "common/log.h" // For _dbg_assert_
+
+#include "common/logging/backend.h"
+#include "common/logging/log.h"
+#include "common/logging/text_formatter.h"
+
+namespace Log {
+
+static std::shared_ptr<Logger> global_logger;
+
+/// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this.
+#define ALL_LOG_CLASSES() \
+ CLS(Log) \
+ CLS(Common) \
+ SUB(Common, Filesystem) \
+ SUB(Common, Memory) \
+ CLS(Core) \
+ SUB(Core, ARM11) \
+ CLS(Config) \
+ CLS(Debug) \
+ SUB(Debug, Emulated) \
+ SUB(Debug, GPU) \
+ SUB(Debug, Breakpoint) \
+ CLS(Kernel) \
+ SUB(Kernel, SVC) \
+ CLS(Service) \
+ SUB(Service, SRV) \
+ SUB(Service, FS) \
+ SUB(Service, APT) \
+ SUB(Service, GSP) \
+ SUB(Service, AC) \
+ SUB(Service, PTM) \
+ SUB(Service, CFG) \
+ SUB(Service, DSP) \
+ SUB(Service, HID) \
+ CLS(HW) \
+ SUB(HW, Memory) \
+ SUB(HW, GPU) \
+ CLS(Frontend) \
+ CLS(Render) \
+ SUB(Render, Software) \
+ SUB(Render, OpenGL) \
+ CLS(Loader)
+
+Logger::Logger() {
+ // Register logging classes so that they can be queried at runtime
+ size_t parent_class;
+ all_classes.reserve((size_t)Class::Count);
+
+#define CLS(x) \
+ all_classes.push_back(Class::x); \
+ parent_class = all_classes.size() - 1;
+#define SUB(x, y) \
+ all_classes.push_back(Class::x##_##y); \
+ all_classes[parent_class].num_children += 1;
+
+ ALL_LOG_CLASSES()
+#undef CLS
+#undef SUB
+
+ // Ensures that ALL_LOG_CLASSES isn't missing any entries.
+ _dbg_assert_(Log, all_classes.size() == (size_t)Class::Count);
+}
+
+// GetClassName is a macro defined by Windows.h, grrr...
+const char* Logger::GetLogClassName(Class log_class) {
+ switch (log_class) {
+#define CLS(x) case Class::x: return #x;
+#define SUB(x, y) case Class::x##_##y: return #x "." #y;
+ ALL_LOG_CLASSES()
+#undef CLS
+#undef SUB
+ }
+ return "Unknown";
+}
+
+const char* Logger::GetLevelName(Level log_level) {
+#define LVL(x) case Level::x: return #x
+ switch (log_level) {
+ LVL(Trace);
+ LVL(Debug);
+ LVL(Info);
+ LVL(Warning);
+ LVL(Error);
+ LVL(Critical);
+ }
+ return "Unknown";
+#undef LVL
+}
+
+void Logger::LogMessage(Entry entry) {
+ ring_buffer.Push(std::move(entry));
+}
+
+size_t Logger::GetEntries(Entry* out_buffer, size_t buffer_len) {
+ return ring_buffer.BlockingPop(out_buffer, buffer_len);
+}
+
+std::shared_ptr<Logger> InitGlobalLogger() {
+ global_logger = std::make_shared<Logger>();
+ return global_logger;
+}
+
+Entry CreateEntry(Class log_class, Level log_level,
+ const char* filename, unsigned int line_nr, const char* function,
+ const char* format, va_list args) {
+ using std::chrono::steady_clock;
+ using std::chrono::duration_cast;
+
+ static steady_clock::time_point time_origin = steady_clock::now();
+
+ std::array<char, 4 * 1024> formatting_buffer;
+
+ Entry entry;
+ entry.timestamp = duration_cast<std::chrono::microseconds>(steady_clock::now() - time_origin);
+ entry.log_class = log_class;
+ entry.log_level = log_level;
+
+ snprintf(formatting_buffer.data(), formatting_buffer.size(), "%s:%s:%u", filename, function, line_nr);
+ entry.location = std::string(formatting_buffer.data());
+
+ vsnprintf(formatting_buffer.data(), formatting_buffer.size(), format, args);
+ entry.message = std::string(formatting_buffer.data());
+
+ return std::move(entry);
+}
+
+void LogMessage(Class log_class, Level log_level,
+ const char* filename, unsigned int line_nr, const char* function,
+ const char* format, ...) {
+ va_list args;
+ va_start(args, format);
+ Entry entry = CreateEntry(log_class, log_level,
+ filename, line_nr, function, format, args);
+ va_end(args);
+
+ if (global_logger != nullptr && !global_logger->IsClosed()) {
+ global_logger->LogMessage(std::move(entry));
+ } else {
+ // Fall back to directly printing to stderr
+ PrintMessage(entry);
+ }
+}
+
+}
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h
new file mode 100644
index 000000000..ae270efe8
--- /dev/null
+++ b/src/common/logging/backend.h
@@ -0,0 +1,134 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <cstdarg>
+#include <memory>
+#include <vector>
+
+#include "common/concurrent_ring_buffer.h"
+
+#include "common/logging/log.h"
+
+namespace Log {
+
+/**
+ * A log entry. Log entries are store in a structured format to permit more varied output
+ * formatting on different frontends, as well as facilitating filtering and aggregation.
+ */
+struct Entry {
+ std::chrono::microseconds timestamp;
+ Class log_class;
+ Level log_level;
+ std::string location;
+ std::string message;
+
+ Entry() = default;
+
+ // TODO(yuriks) Use defaulted move constructors once MSVC supports them
+#define MOVE(member) member(std::move(o.member))
+ Entry(Entry&& o)
+ : MOVE(timestamp), MOVE(log_class), MOVE(log_level),
+ MOVE(location), MOVE(message)
+ {}
+#undef MOVE
+
+ Entry& operator=(const Entry&& o) {
+#define MOVE(member) member = std::move(o.member)
+ MOVE(timestamp);
+ MOVE(log_class);
+ MOVE(log_level);
+ MOVE(location);
+ MOVE(message);
+#undef MOVE
+ return *this;
+ }
+};
+
+struct ClassInfo {
+ Class log_class;
+
+ /**
+ * Total number of (direct or indirect) sub classes this class has. If any, they follow in
+ * sequence after this class in the class list.
+ */
+ unsigned int num_children = 0;
+
+ ClassInfo(Class log_class) : log_class(log_class) {}
+};
+
+/**
+ * Logging management class. This class has the dual purpose of acting as an exchange point between
+ * the logging clients and the log outputter, as well as containing reflection info about available
+ * log classes.
+ */
+class Logger {
+private:
+ using Buffer = Common::ConcurrentRingBuffer<Entry, 16 * 1024 / sizeof(Entry)>;
+
+public:
+ static const size_t QUEUE_CLOSED = Buffer::QUEUE_CLOSED;
+
+ Logger();
+
+ /**
+ * Returns a list of all vector classes and subclasses. The sequence returned is a pre-order of
+ * classes and subclasses, which together with the `num_children` field in ClassInfo, allows
+ * you to recover the hierarchy.
+ */
+ const std::vector<ClassInfo>& GetClasses() const { return all_classes; }
+
+ /**
+ * Returns the name of the passed log class as a C-string. Subclasses are separated by periods
+ * instead of underscores as in the enumeration.
+ */
+ static const char* GetLogClassName(Class log_class);
+
+ /**
+ * Returns the name of the passed log level as a C-string.
+ */
+ static const char* GetLevelName(Level log_level);
+
+ /**
+ * Appends a messages to the log buffer.
+ * @note This function is thread safe.
+ */
+ void LogMessage(Entry entry);
+
+ /**
+ * Retrieves a batch of messages from the log buffer, blocking until they are available.
+ * @note This function is thread safe.
+ *
+ * @param out_buffer Destination buffer that will receive the log entries.
+ * @param buffer_len The maximum size of `out_buffer`.
+ * @return The number of entries stored. In case the logger is shutting down, `QUEUE_CLOSED` is
+ * returned, no entries are stored and the logger should shutdown.
+ */
+ size_t GetEntries(Entry* out_buffer, size_t buffer_len);
+
+ /**
+ * Initiates a shutdown of the logger. This will indicate to log output clients that they
+ * should shutdown.
+ */
+ void Close() { ring_buffer.Close(); }
+
+ /**
+ * Returns true if Close() has already been called on the Logger.
+ */
+ bool IsClosed() const { return ring_buffer.IsClosed(); }
+
+private:
+ Buffer ring_buffer;
+ std::vector<ClassInfo> all_classes;
+};
+
+/// Creates a log entry by formatting the given source location, and message.
+Entry CreateEntry(Class log_class, Level log_level,
+ const char* filename, unsigned int line_nr, const char* function,
+ const char* format, va_list args);
+/// Initializes the default Logger.
+std::shared_ptr<Logger> InitGlobalLogger();
+
+}
diff --git a/src/common/logging/filter.cpp b/src/common/logging/filter.cpp
new file mode 100644
index 000000000..0cf9b05e7
--- /dev/null
+++ b/src/common/logging/filter.cpp
@@ -0,0 +1,132 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include <algorithm>
+
+#include "common/logging/filter.h"
+#include "common/logging/backend.h"
+#include "common/string_util.h"
+
+namespace Log {
+
+Filter::Filter(Level default_level) {
+ ResetAll(default_level);
+}
+
+void Filter::ResetAll(Level level) {
+ class_levels.fill(level);
+}
+
+void Filter::SetClassLevel(Class log_class, Level level) {
+ class_levels[static_cast<size_t>(log_class)] = level;
+}
+
+void Filter::SetSubclassesLevel(const ClassInfo& log_class, Level level) {
+ const size_t log_class_i = static_cast<size_t>(log_class.log_class);
+
+ const size_t begin = log_class_i + 1;
+ const size_t end = begin + log_class.num_children;
+ for (size_t i = begin; begin < end; ++i) {
+ class_levels[i] = level;
+ }
+}
+
+void Filter::ParseFilterString(const std::string& filter_str) {
+ auto clause_begin = filter_str.cbegin();
+ while (clause_begin != filter_str.cend()) {
+ auto clause_end = std::find(clause_begin, filter_str.cend(), ' ');
+
+ // If clause isn't empty
+ if (clause_end != clause_begin) {
+ ParseFilterRule(clause_begin, clause_end);
+ }
+
+ if (clause_end != filter_str.cend()) {
+ // Skip over the whitespace
+ ++clause_end;
+ }
+ clause_begin = clause_end;
+ }
+}
+
+template <typename It>
+static Level GetLevelByName(const It begin, const It end) {
+ for (u8 i = 0; i < static_cast<u8>(Level::Count); ++i) {
+ const char* level_name = Logger::GetLevelName(static_cast<Level>(i));
+ if (Common::ComparePartialString(begin, end, level_name)) {
+ return static_cast<Level>(i);
+ }
+ }
+ return Level::Count;
+}
+
+template <typename It>
+static Class GetClassByName(const It begin, const It end) {
+ for (ClassType i = 0; i < static_cast<ClassType>(Class::Count); ++i) {
+ const char* level_name = Logger::GetLogClassName(static_cast<Class>(i));
+ if (Common::ComparePartialString(begin, end, level_name)) {
+ return static_cast<Class>(i);
+ }
+ }
+ return Class::Count;
+}
+
+template <typename InputIt, typename T>
+static InputIt find_last(InputIt begin, const InputIt end, const T& value) {
+ auto match = end;
+ while (begin != end) {
+ auto new_match = std::find(begin, end, value);
+ if (new_match != end) {
+ match = new_match;
+ ++new_match;
+ }
+ begin = new_match;
+ }
+ return match;
+}
+
+bool Filter::ParseFilterRule(const std::string::const_iterator begin,
+ const std::string::const_iterator end) {
+ auto level_separator = std::find(begin, end, ':');
+ if (level_separator == end) {
+ LOG_ERROR(Log, "Invalid log filter. Must specify a log level after `:`: %s",
+ std::string(begin, end).c_str());
+ return false;
+ }
+
+ const Level level = GetLevelByName(level_separator + 1, end);
+ if (level == Level::Count) {
+ LOG_ERROR(Log, "Unknown log level in filter: %s", std::string(begin, end).c_str());
+ return false;
+ }
+
+ if (Common::ComparePartialString(begin, level_separator, "*")) {
+ ResetAll(level);
+ return true;
+ }
+
+ auto class_name_end = find_last(begin, level_separator, '.');
+ if (class_name_end != level_separator &&
+ !Common::ComparePartialString(class_name_end + 1, level_separator, "*")) {
+ class_name_end = level_separator;
+ }
+
+ const Class log_class = GetClassByName(begin, class_name_end);
+ if (log_class == Class::Count) {
+ LOG_ERROR(Log, "Unknown log class in filter: %s", std::string(begin, end).c_str());
+ return false;
+ }
+
+ if (class_name_end == level_separator) {
+ SetClassLevel(log_class, level);
+ }
+ SetSubclassesLevel(log_class, level);
+ return true;
+}
+
+bool Filter::CheckMessage(Class log_class, Level level) const {
+ return static_cast<u8>(level) >= static_cast<u8>(class_levels[static_cast<size_t>(log_class)]);
+}
+
+}
diff --git a/src/common/logging/filter.h b/src/common/logging/filter.h
new file mode 100644
index 000000000..32b14b159
--- /dev/null
+++ b/src/common/logging/filter.h
@@ -0,0 +1,63 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include <array>
+#include <string>
+
+#include "common/logging/log.h"
+
+namespace Log {
+
+struct ClassInfo;
+
+/**
+ * Implements a log message filter which allows different log classes to have different minimum
+ * severity levels. The filter can be changed at runtime and can be parsed from a string to allow
+ * editing via the interface or loading from a configuration file.
+ */
+class Filter {
+public:
+ /// Initializes the filter with all classes having `default_level` as the minimum level.
+ Filter(Level default_level);
+
+ /// Resets the filter so that all classes have `level` as the minimum displayed level.
+ void ResetAll(Level level);
+ /// Sets the minimum level of `log_class` (and not of its subclasses) to `level`.
+ void SetClassLevel(Class log_class, Level level);
+ /**
+ * Sets the minimum level of all of `log_class` subclasses to `level`. The level of `log_class`
+ * itself is not changed.
+ */
+ void SetSubclassesLevel(const ClassInfo& log_class, Level level);
+
+ /**
+ * Parses a filter string and applies it to this filter.
+ *
+ * A filter string consists of a space-separated list of filter rules, each of the format
+ * `<class>:<level>`. `<class>` is a log class name, with subclasses separated using periods.
+ * A rule for a given class also affects all of its subclasses. `*` wildcards are allowed and
+ * can be used to apply a rule to all classes or to all subclasses of a class without affecting
+ * the parent class. `<level>` a severity level name which will be set as the minimum logging
+ * level of the matched classes. Rules are applied left to right, with each rule overriding
+ * previous ones in the sequence.
+ *
+ * A few examples of filter rules:
+ * - `*:Info` -- Resets the level of all classes to Info.
+ * - `Service:Info` -- Sets the level of Service and all subclasses (Service.FS, Service.APT,
+ * etc.) to Info.
+ * - `Service.*:Debug` -- Sets the level of all Service subclasses to Debug, while leaving the
+ * level of Service unchanged.
+ * - `Service.FS:Trace` -- Sets the level of the Service.FS class to Trace.
+ */
+ void ParseFilterString(const std::string& filter_str);
+ bool ParseFilterRule(const std::string::const_iterator start, const std::string::const_iterator end);
+
+ /// Matches class/level combination against the filter, returning true if it passed.
+ bool CheckMessage(Class log_class, Level level) const;
+
+private:
+ std::array<Level, (size_t)Class::Count> class_levels;
+};
+
+}
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
new file mode 100644
index 000000000..1eec34fbb
--- /dev/null
+++ b/src/common/logging/log.h
@@ -0,0 +1,115 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <cassert>
+#include <chrono>
+#include <string>
+
+#include "common/common_types.h"
+
+namespace Log {
+
+/// Specifies the severity or level of detail of the log message.
+enum class Level : u8 {
+ Trace, ///< Extremely detailed and repetitive debugging information that is likely to
+ /// pollute logs.
+ Debug, ///< Less detailed debugging information.
+ Info, ///< Status information from important points during execution.
+ Warning, ///< Minor or potential problems found during execution of a task.
+ Error, ///< Major problems found during execution of a task that prevent it from being
+ /// completed.
+ Critical, ///< Major problems during execution that threathen the stability of the entire
+ /// application.
+
+ Count ///< Total number of logging levels
+};
+
+typedef u8 ClassType;
+
+/**
+ * Specifies the sub-system that generated the log message.
+ *
+ * @note If you add a new entry here, also add a corresponding one to `ALL_LOG_CLASSES` in log.cpp.
+ */
+enum class Class : ClassType {
+ Log, ///< Messages about the log system itself
+ Common, ///< Library routines
+ Common_Filesystem, ///< Filesystem interface library
+ Common_Memory, ///< Memory mapping and management functions
+ Core, ///< LLE emulation core
+ Core_ARM11, ///< ARM11 CPU core
+ Config, ///< Emulator configuration (including commandline)
+ Debug, ///< Debugging tools
+ Debug_Emulated, ///< Debug messages from the emulated programs
+ Debug_GPU, ///< GPU debugging tools
+ Debug_Breakpoint, ///< Logging breakpoints and watchpoints
+ Kernel, ///< The HLE implementation of the CTR kernel
+ Kernel_SVC, ///< Kernel system calls
+ Service, ///< HLE implementation of system services. Each major service
+ /// should have its own subclass.
+ Service_SRV, ///< The SRV (Service Directory) implementation
+ Service_FS, ///< The FS (Filesystem) service implementation
+ Service_APT, ///< The APT (Applets) service
+ Service_GSP, ///< The GSP (GPU control) service
+ Service_AC, ///< The AC (WiFi status) service
+ Service_PTM, ///< The PTM (Power status & misc.) service
+ Service_CFG, ///< The CFG (Configuration) service
+ Service_DSP, ///< The DSP (DSP control) service
+ Service_HID, ///< The HID (User input) service
+ HW, ///< Low-level hardware emulation
+ HW_Memory, ///< Memory-map and address translation
+ HW_GPU, ///< GPU control emulation
+ Frontend, ///< Emulator UI
+ Render, ///< Emulator video output and hardware acceleration
+ Render_Software, ///< Software renderer backend
+ Render_OpenGL, ///< OpenGL backend
+ Loader, ///< ROM loader
+
+ Count ///< Total number of logging classes
+};
+
+/**
+ * Level below which messages are simply discarded without buffering regardless of the display
+ * settings.
+ */
+const Level MINIMUM_LEVEL =
+#ifdef _DEBUG
+ Level::Trace;
+#else
+ Level::Debug;
+#endif
+
+/**
+ * Logs a message to the global logger. This proxy exists to avoid exposing the details of the
+ * Logger class, including the ConcurrentRingBuffer template, to all files that desire to log
+ * messages, reducing unecessary recompilations.
+ */
+void LogMessage(Class log_class, Level log_level,
+ const char* filename, unsigned int line_nr, const char* function,
+#ifdef _MSC_VER
+ _Printf_format_string_
+#endif
+ const char* format, ...)
+#ifdef __GNUC__
+ __attribute__((format(printf, 6, 7)))
+#endif
+ ;
+
+} // namespace Log
+
+#define LOG_GENERIC(log_class, log_level, ...) \
+ do { \
+ if (::Log::Level::log_level >= ::Log::MINIMUM_LEVEL) \
+ ::Log::LogMessage(::Log::Class::log_class, ::Log::Level::log_level, \
+ __FILE__, __LINE__, __func__, __VA_ARGS__); \
+ } while (0)
+
+#define LOG_TRACE( log_class, ...) LOG_GENERIC(log_class, Trace, __VA_ARGS__)
+#define LOG_DEBUG( log_class, ...) LOG_GENERIC(log_class, Debug, __VA_ARGS__)
+#define LOG_INFO( log_class, ...) LOG_GENERIC(log_class, Info, __VA_ARGS__)
+#define LOG_WARNING( log_class, ...) LOG_GENERIC(log_class, Warning, __VA_ARGS__)
+#define LOG_ERROR( log_class, ...) LOG_GENERIC(log_class, Error, __VA_ARGS__)
+#define LOG_CRITICAL(log_class, ...) LOG_GENERIC(log_class, Critical, __VA_ARGS__)
diff --git a/src/common/logging/text_formatter.cpp b/src/common/logging/text_formatter.cpp
new file mode 100644
index 000000000..f6b02fd47
--- /dev/null
+++ b/src/common/logging/text_formatter.cpp
@@ -0,0 +1,136 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#include <array>
+#include <cstdio>
+
+#ifdef _WIN32
+# define WIN32_LEAN_AND_MEAN
+# include <Windows.h>
+#endif
+
+#include "common/logging/backend.h"
+#include "common/logging/filter.h"
+#include "common/logging/log.h"
+#include "common/logging/text_formatter.h"
+
+#include "common/string_util.h"
+
+namespace Log {
+
+// TODO(bunnei): This should be moved to a generic path manipulation library
+const char* TrimSourcePath(const char* path, const char* root) {
+ const char* p = path;
+
+ while (*p != '\0') {
+ const char* next_slash = p;
+ while (*next_slash != '\0' && *next_slash != '/' && *next_slash != '\\') {
+ ++next_slash;
+ }
+
+ bool is_src = Common::ComparePartialString(p, next_slash, root);
+ p = next_slash;
+
+ if (*p != '\0') {
+ ++p;
+ }
+ if (is_src) {
+ path = p;
+ }
+ }
+ return path;
+}
+
+void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len) {
+ unsigned int time_seconds = static_cast<unsigned int>(entry.timestamp.count() / 1000000);
+ unsigned int time_fractional = static_cast<unsigned int>(entry.timestamp.count() % 1000000);
+
+ const char* class_name = Logger::GetLogClassName(entry.log_class);
+ const char* level_name = Logger::GetLevelName(entry.log_level);
+
+ snprintf(out_text, text_len, "[%4u.%06u] %s <%s> %s: %s",
+ time_seconds, time_fractional, class_name, level_name,
+ TrimSourcePath(entry.location.c_str()), entry.message.c_str());
+}
+
+void PrintMessage(const Entry& entry) {
+ std::array<char, 4 * 1024> format_buffer;
+ FormatLogMessage(entry, format_buffer.data(), format_buffer.size());
+ fputs(format_buffer.data(), stderr);
+ fputc('\n', stderr);
+}
+
+void PrintColoredMessage(const Entry& entry) {
+#ifdef _WIN32
+ static HANDLE console_handle = GetStdHandle(STD_ERROR_HANDLE);
+
+ CONSOLE_SCREEN_BUFFER_INFO original_info = {0};
+ GetConsoleScreenBufferInfo(console_handle, &original_info);
+
+ WORD color = 0;
+ switch (entry.log_level) {
+ case Level::Trace: // Grey
+ color = FOREGROUND_INTENSITY; break;
+ case Level::Debug: // Cyan
+ color = FOREGROUND_GREEN | FOREGROUND_BLUE; break;
+ case Level::Info: // Bright gray
+ color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE; break;
+ case Level::Warning: // Bright yellow
+ color = FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY; break;
+ case Level::Error: // Bright red
+ color = FOREGROUND_RED | FOREGROUND_INTENSITY; break;
+ case Level::Critical: // Bright magenta
+ color = FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY; break;
+ }
+
+ SetConsoleTextAttribute(console_handle, color);
+#else
+# define ESC "\x1b"
+ const char* color = "";
+ switch (entry.log_level) {
+ case Level::Trace: // Grey
+ color = ESC "[1;30m"; break;
+ case Level::Debug: // Cyan
+ color = ESC "[0;36m"; break;
+ case Level::Info: // Bright gray
+ color = ESC "[0;37m"; break;
+ case Level::Warning: // Bright yellow
+ color = ESC "[1;33m"; break;
+ case Level::Error: // Bright red
+ color = ESC "[1;31m"; break;
+ case Level::Critical: // Bright magenta
+ color = ESC "[1;35m"; break;
+ }
+
+ fputs(color, stderr);
+#endif
+
+ PrintMessage(entry);
+
+#ifdef _WIN32
+ SetConsoleTextAttribute(console_handle, original_info.wAttributes);
+#else
+ fputs(ESC "[0m", stderr);
+# undef ESC
+#endif
+}
+
+void TextLoggingLoop(std::shared_ptr<Logger> logger, const Filter* filter) {
+ std::array<Entry, 256> entry_buffer;
+
+ while (true) {
+ size_t num_entries = logger->GetEntries(entry_buffer.data(), entry_buffer.size());
+ if (num_entries == Logger::QUEUE_CLOSED) {
+ break;
+ }
+ for (size_t i = 0; i < num_entries; ++i) {
+ const Entry& entry = entry_buffer[i];
+ if (filter->CheckMessage(entry.log_class, entry.log_level)) {
+ PrintColoredMessage(entry);
+ }
+ }
+ }
+}
+
+}
diff --git a/src/common/logging/text_formatter.h b/src/common/logging/text_formatter.h
new file mode 100644
index 000000000..1f73ca44a
--- /dev/null
+++ b/src/common/logging/text_formatter.h
@@ -0,0 +1,41 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include <cstddef>
+#include <memory>
+
+namespace Log {
+
+class Logger;
+struct Entry;
+class Filter;
+
+/**
+ * Attempts to trim an arbitrary prefix from `path`, leaving only the part starting at `root`. It's
+ * intended to be used to strip a system-specific build directory from the `__FILE__` macro,
+ * leaving only the path relative to the sources root.
+ *
+ * @param path The input file path as a null-terminated string
+ * @param root The name of the root source directory as a null-terminated string. Path up to and
+ * including the last occurence of this name will be stripped
+ * @return A pointer to the same string passed as `path`, but starting at the trimmed portion
+ */
+const char* TrimSourcePath(const char* path, const char* root = "src");
+
+/// Formats a log entry into the provided text buffer.
+void FormatLogMessage(const Entry& entry, char* out_text, size_t text_len);
+/// Formats and prints a log entry to stderr.
+void PrintMessage(const Entry& entry);
+/// Prints the same message as `PrintMessage`, but colored acoording to the severity level.
+void PrintColoredMessage(const Entry& entry);
+
+/**
+ * Logging loop that repeatedly reads messages from the provided logger and prints them to the
+ * console. It is the baseline barebones log outputter.
+ */
+void TextLoggingLoop(std::shared_ptr<Logger> logger, const Filter* filter);
+
+}
diff --git a/src/common/math_util.cpp b/src/common/math_util.cpp
index ab0e6b75c..3613e82a6 100644
--- a/src/common/math_util.cpp
+++ b/src/common/math_util.cpp
@@ -18,7 +18,7 @@ u32 ClassifyDouble(double dvalue)
value.d = dvalue;
u64 sign = value.i & DOUBLE_SIGN;
u64 exp = value.i & DOUBLE_EXP;
- if (exp > DOUBLE_ZERO && exp < DOUBLE_EXP)
+ if (exp > DOUBLE_ZERO && exp < DOUBLE_EXP)
{
// Nice normalized number.
return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN;
@@ -58,7 +58,7 @@ u32 ClassifyFloat(float fvalue)
value.f = fvalue;
u32 sign = value.i & FLOAT_SIGN;
u32 exp = value.i & FLOAT_EXP;
- if (exp > FLOAT_ZERO && exp < FLOAT_EXP)
+ if (exp > FLOAT_ZERO && exp < FLOAT_EXP)
{
// Nice normalized number.
return sign ? PPC_FPCLASS_NN : PPC_FPCLASS_PN;
@@ -77,13 +77,13 @@ u32 ClassifyFloat(float fvalue)
// Denormalized number.
return sign ? PPC_FPCLASS_ND : PPC_FPCLASS_PD;
}
- }
- else if (exp)
+ }
+ else if (exp)
{
// Infinite
return sign ? PPC_FPCLASS_NINF : PPC_FPCLASS_PINF;
- }
- else
+ }
+ else
{
//Zero
return sign ? PPC_FPCLASS_NZ : PPC_FPCLASS_PZ;
@@ -143,7 +143,7 @@ void Matrix33::RotateY(Matrix33 &mtx, float rad)
mtx.data[0] = c;
mtx.data[2] = s;
mtx.data[4] = 1;
- mtx.data[6] = -s;
+ mtx.data[6] = -s;
mtx.data[8] = c;
}
diff --git a/src/common/math_util.h b/src/common/math_util.h
index b32e7bb14..b10a25c13 100644
--- a/src/common/math_util.h
+++ b/src/common/math_util.h
@@ -7,6 +7,7 @@
#include "common/common.h"
#include <algorithm>
+#include <type_traits>
#include <vector>
namespace MathUtil
@@ -109,11 +110,11 @@ struct Rectangle
Rectangle(T theLeft, T theTop, T theRight, T theBottom)
: left(theLeft), top(theTop), right(theRight), bottom(theBottom)
{ }
-
+
bool operator==(const Rectangle& r) { return left==r.left && top==r.top && right==r.right && bottom==r.bottom; }
- T GetWidth() const { return abs(right - left); }
- T GetHeight() const { return abs(bottom - top); }
+ T GetWidth() const { return std::abs(static_cast<typename std::make_signed<T>::type>(right - left)); }
+ T GetHeight() const { return std::abs(static_cast<typename std::make_signed<T>::type>(bottom - top)); }
// If the rectangle is in a coordinate system with a lower-left origin, use
// this Clamp.
@@ -127,7 +128,7 @@ struct Rectangle
// If the rectangle is in a coordinate system with an upper-left origin,
// use this Clamp.
- void ClampUL(T x1, T y1, T x2, T y2)
+ void ClampUL(T x1, T y1, T x2, T y2)
{
if (left < x1) left = x1;
if (right > x2) right = x2;
diff --git a/src/common/mem_arena.cpp b/src/common/mem_arena.cpp
index 40d9c03a2..9904d2472 100644
--- a/src/common/mem_arena.cpp
+++ b/src/common/mem_arena.cpp
@@ -30,7 +30,7 @@
#endif
#ifdef IOS
-void* globalbase = NULL;
+void* globalbase = nullptr;
#endif
#ifdef ANDROID
@@ -38,7 +38,7 @@ void* globalbase = NULL;
// Hopefully this ABI will never change...
-#define ASHMEM_DEVICE "/dev/ashmem"
+#define ASHMEM_DEVICE "/dev/ashmem"
/*
* ashmem_create_region - creates a new ashmem region and returns the file
@@ -71,7 +71,7 @@ int ashmem_create_region(const char *name, size_t size)
return fd;
error:
- ERROR_LOG(MEMMAP, "NASTY ASHMEM ERROR: ret = %08x", ret);
+ LOG_ERROR(Common_Memory, "NASTY ASHMEM ERROR: ret = %08x", ret);
close(fd);
return ret;
}
@@ -121,7 +121,7 @@ void MemArena::GrabLowMemSpace(size_t size)
{
#ifdef _WIN32
#ifndef _XBOX
- hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, (DWORD)(size), NULL);
+ hMemoryMapping = CreateFileMapping(INVALID_HANDLE_VALUE, nullptr, PAGE_READWRITE, 0, (DWORD)(size), nullptr);
GetSystemInfo(&sysInfo);
#endif
#elif defined(ANDROID)
@@ -130,7 +130,7 @@ void MemArena::GrabLowMemSpace(size_t size)
// Note that it appears that ashmem is pinned by default, so no need to pin.
if (fd < 0)
{
- ERROR_LOG(MEMMAP, "Failed to grab ashmem space of size: %08x errno: %d", (int)size, (int)(errno));
+ LOG_ERROR(Common_Memory, "Failed to grab ashmem space of size: %08x errno: %d", (int)size, (int)(errno));
return;
}
#else
@@ -148,12 +148,12 @@ void MemArena::GrabLowMemSpace(size_t size)
}
else if (errno != EEXIST)
{
- ERROR_LOG(MEMMAP, "shm_open failed: %s", strerror(errno));
+ LOG_ERROR(Common_Memory, "shm_open failed: %s", strerror(errno));
return;
}
}
if (ftruncate(fd, size) < 0)
- ERROR_LOG(MEMMAP, "Failed to allocate low memory space");
+ LOG_ERROR(Common_Memory, "Failed to allocate low memory space");
#endif
}
@@ -178,7 +178,7 @@ void *MemArena::CreateView(s64 offset, size_t size, void *base)
#ifdef _XBOX
size = roundup(size);
// use 64kb pages
- void * ptr = VirtualAlloc(NULL, size, MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
+ void * ptr = VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
return ptr;
#else
size = roundup(size);
@@ -197,7 +197,7 @@ void *MemArena::CreateView(s64 offset, size_t size, void *base)
if (retval == MAP_FAILED)
{
- NOTICE_LOG(MEMMAP, "mmap failed");
+ LOG_ERROR(Common_Memory, "mmap failed");
return nullptr;
}
return retval;
@@ -243,8 +243,8 @@ u8* MemArena::Find4GBBase()
return base;
#else
#ifdef IOS
- void* base = NULL;
- if (globalbase == NULL){
+ void* base = nullptr;
+ if (globalbase == nullptr){
base = mmap(0, 0x08000000, PROT_READ | PROT_WRITE,
MAP_ANON | MAP_SHARED, -1, 0);
if (base == MAP_FAILED) {
@@ -272,11 +272,11 @@ u8* MemArena::Find4GBBase()
// yeah, this could also be done in like two bitwise ops...
-#define SKIP(a_flags, b_flags)
-// if (!(a_flags & MV_WII_ONLY) && (b_flags & MV_WII_ONLY))
-// continue;
-// if (!(a_flags & MV_FAKE_VMEM) && (b_flags & MV_FAKE_VMEM))
-// continue;
+#define SKIP(a_flags, b_flags)
+//if (!(a_flags & MV_WII_ONLY) && (b_flags & MV_WII_ONLY))
+// continue;
+//if (!(a_flags & MV_FAKE_VMEM) && (b_flags & MV_FAKE_VMEM))
+// continue;
static bool Memory_TryBase(u8 *base, const MemoryView *views, int num_views, u32 flags, MemArena *arena) {
// OK, we know where to find free space. Now grab it!
@@ -357,7 +357,7 @@ bail:
if (views[j].out_ptr_low && *views[j].out_ptr_low)
{
arena->ReleaseView(*views[j].out_ptr_low, views[j].size);
- *views[j].out_ptr_low = NULL;
+ *views[j].out_ptr_low = nullptr;
}
if (*views[j].out_ptr)
{
@@ -369,7 +369,7 @@ bail:
arena->ReleaseView(*views[j].out_ptr, views[j].size);
}
#endif
- *views[j].out_ptr = NULL;
+ *views[j].out_ptr = nullptr;
}
}
return false;
@@ -415,7 +415,7 @@ u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena
#elif defined(_WIN32)
// Try a whole range of possible bases. Return once we got a valid one.
u32 max_base_addr = 0x7FFF0000 - 0x10000000;
- u8 *base = NULL;
+ u8 *base = nullptr;
for (u32 base_addr = 0x01000000; base_addr < max_base_addr; base_addr += 0x400000)
{
@@ -423,7 +423,7 @@ u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena
base = (u8 *)base_addr;
if (Memory_TryBase(base, views, num_views, flags, arena))
{
- INFO_LOG(MEMMAP, "Found valid memory base at %p after %i tries.", base, base_attempts);
+ LOG_DEBUG(Common_Memory, "Found valid memory base at %p after %i tries.", base, base_attempts);
base_attempts = 0;
break;
}
@@ -442,7 +442,7 @@ u8 *MemoryMap_Setup(const MemoryView *views, int num_views, u32 flags, MemArena
u8 *base = MemArena::Find4GBBase();
if (!Memory_TryBase(base, views, num_views, flags, arena))
{
- ERROR_LOG(MEMMAP, "MemoryMap_Setup: Failed finding a memory base.");
+ LOG_ERROR(Common_Memory, "MemoryMap_Setup: Failed finding a memory base.");
PanicAlert("MemoryMap_Setup: Failed finding a memory base.");
return 0;
}
@@ -463,8 +463,8 @@ void MemoryMap_Shutdown(const MemoryView *views, int num_views, u32 flags, MemAr
arena->ReleaseView(*views[i].out_ptr_low, views[i].size);
if (*views[i].out_ptr && (views[i].out_ptr_low && *views[i].out_ptr != *views[i].out_ptr_low))
arena->ReleaseView(*views[i].out_ptr, views[i].size);
- *views[i].out_ptr = NULL;
+ *views[i].out_ptr = nullptr;
if (views[i].out_ptr_low)
- *views[i].out_ptr_low = NULL;
+ *views[i].out_ptr_low = nullptr;
}
}
diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp
index bab7d9f7a..ca8a2a9e4 100644
--- a/src/common/memory_util.cpp
+++ b/src/common/memory_util.cpp
@@ -47,7 +47,7 @@ void* AllocateExecutableMemory(size_t size, bool low)
// printf("Mapped executable memory at %p (size %ld)\n", ptr,
// (unsigned long)size);
-
+
#ifdef _WIN32
if (ptr == nullptr)
{
@@ -55,7 +55,7 @@ void* AllocateExecutableMemory(size_t size, bool low)
if (ptr == MAP_FAILED)
{
ptr = nullptr;
-#endif
+#endif
PanicAlert("Failed to allocate executable memory");
}
#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
@@ -93,7 +93,7 @@ void* AllocateMemoryPages(size_t size)
// printf("Mapped memory at %p (size %ld)\n", ptr,
// (unsigned long)size);
- if (ptr == NULL)
+ if (ptr == nullptr)
PanicAlert("Failed to allocate raw memory");
return ptr;
@@ -104,19 +104,19 @@ void* AllocateAlignedMemory(size_t size,size_t alignment)
#ifdef _WIN32
void* ptr = _aligned_malloc(size,alignment);
#else
- void* ptr = NULL;
+ void* ptr = nullptr;
#ifdef ANDROID
ptr = memalign(alignment, size);
#else
if (posix_memalign(&ptr, alignment, size) != 0)
- ERROR_LOG(MEMMAP, "Failed to allocate aligned memory");
+ LOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
#endif
#endif
// printf("Mapped memory at %p (size %ld)\n", ptr,
// (unsigned long)size);
- if (ptr == NULL)
+ if (ptr == nullptr)
PanicAlert("Failed to allocate aligned memory");
return ptr;
@@ -127,11 +127,11 @@ void FreeMemoryPages(void* ptr, size_t size)
if (ptr)
{
#ifdef _WIN32
-
+
if (!VirtualFree(ptr, 0, MEM_RELEASE))
PanicAlert("FreeMemoryPages failed!\n%s", GetLastErrorMsg());
- ptr = NULL; // Is this our responsibility?
-
+ ptr = nullptr; // Is this our responsibility?
+
#else
munmap(ptr, size);
#endif
@@ -184,7 +184,7 @@ std::string MemUsage()
// Print information about the memory usage of the process.
hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
- if (NULL == hProcess) return "MemUsage Error";
+ if (nullptr == hProcess) return "MemUsage Error";
if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
Ret = Common::StringFromFormat("%s K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7).c_str());
diff --git a/src/common/misc.cpp b/src/common/misc.cpp
index cf6df44e8..bc9d26188 100644
--- a/src/common/misc.cpp
+++ b/src/common/misc.cpp
@@ -23,9 +23,9 @@ const char* GetLastErrorMsg()
#ifdef _WIN32
static __declspec(thread) char err_str[buff_size] = {};
- FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(),
+ FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
- err_str, buff_size, NULL);
+ err_str, buff_size, nullptr);
#else
static __thread char err_str[buff_size] = {};
diff --git a/src/common/msg_handler.cpp b/src/common/msg_handler.cpp
index b3556aaa8..7ffedc45a 100644
--- a/src/common/msg_handler.cpp
+++ b/src/common/msg_handler.cpp
@@ -75,7 +75,7 @@ bool MsgAlert(bool yes_no, int Style, const char* format, ...)
Common::CharArrayFromFormatV(buffer, sizeof(buffer)-1, str_translator(format).c_str(), args);
va_end(args);
- ERROR_LOG(MASTER_LOG, "%s: %s", caption.c_str(), buffer);
+ LOG_INFO(Common, "%s: %s", caption.c_str(), buffer);
// Don't ignore questions, especially AskYesNo, PanicYesNo could be ignored
if (msg_handler && (AlertEnabled || Style == QUESTION || Style == CRITICAL))
diff --git a/src/common/msg_handler.h b/src/common/msg_handler.h
index 7c5319ec3..9bfdf950e 100644
--- a/src/common/msg_handler.h
+++ b/src/common/msg_handler.h
@@ -15,7 +15,7 @@ enum MSG_TYPE
CRITICAL
};
-typedef bool (*MsgAlertHandler)(const char* caption, const char* text,
+typedef bool (*MsgAlertHandler)(const char* caption, const char* text,
bool yes_no, int Style);
typedef std::string (*StringTranslator)(const char* text);
@@ -31,29 +31,29 @@ void SetEnableAlert(bool enable);
#ifndef GEKKO
#ifdef _WIN32
- #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__)
- #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__)
- #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__)
- #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__)
- #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__)
+ #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__)
+ #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__)
+ #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__)
+ #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__)
+ #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__)
// Use these macros (that do the same thing) if the message should be translated.
- #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__)
- #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__)
- #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__)
- #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__)
- #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__)
+ #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, __VA_ARGS__)
+ #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, __VA_ARGS__)
+ #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, __VA_ARGS__)
+ #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, __VA_ARGS__)
+ #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, __VA_ARGS__)
#else
- #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__)
- #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__)
- #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__)
- #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__)
- #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__)
+ #define SuccessAlert(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__)
+ #define PanicAlert(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__)
+ #define PanicYesNo(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__)
+ #define AskYesNo(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__)
+ #define CriticalAlert(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__)
// Use these macros (that do the same thing) if the message should be translated.
- #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__)
- #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__)
- #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__)
- #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__)
- #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__)
+ #define SuccessAlertT(format, ...) MsgAlert(false, INFORMATION, format, ##__VA_ARGS__)
+ #define PanicAlertT(format, ...) MsgAlert(false, WARNING, format, ##__VA_ARGS__)
+ #define PanicYesNoT(format, ...) MsgAlert(true, WARNING, format, ##__VA_ARGS__)
+ #define AskYesNoT(format, ...) MsgAlert(true, QUESTION, format, ##__VA_ARGS__)
+ #define CriticalAlertT(format, ...) MsgAlert(false, CRITICAL, format, ##__VA_ARGS__)
#endif
#else
// GEKKO
diff --git a/src/common/platform.h b/src/common/platform.h
index d9f095433..53d98fe74 100644
--- a/src/common/platform.h
+++ b/src/common/platform.h
@@ -77,7 +77,7 @@
inline struct tm* localtime_r(const time_t *clock, struct tm *result) {
if (localtime_s(result, clock) == 0)
return result;
- return NULL;
+ return nullptr;
}
#else
diff --git a/src/common/scope_exit.h b/src/common/scope_exit.h
new file mode 100644
index 000000000..1d3e59319
--- /dev/null
+++ b/src/common/scope_exit.h
@@ -0,0 +1,37 @@
+// Copyright 2014 Citra Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+namespace detail {
+ template <typename Func>
+ struct ScopeExitHelper {
+ explicit ScopeExitHelper(Func&& func) : func(std::move(func)) {}
+ ~ScopeExitHelper() { func(); }
+
+ Func func;
+ };
+
+ template <typename Func>
+ ScopeExitHelper<Func> ScopeExit(Func&& func) { return ScopeExitHelper<Func>(std::move(func)); }
+}
+
+/**
+ * This macro allows you to conveniently specify a block of code that will run on scope exit. Handy
+ * for doing ad-hoc clean-up tasks in a function with multiple returns.
+ *
+ * Example usage:
+ * \code
+ * const int saved_val = g_foo;
+ * g_foo = 55;
+ * SCOPE_EXIT({ g_foo = saved_val; });
+ *
+ * if (Bar()) {
+ * return 0;
+ * } else {
+ * return 20;
+ * }
+ * \endcode
+ */
+#define SCOPE_EXIT(body) auto scope_exit_helper_##__LINE__ = detail::ScopeExit([&]() body)
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index 61f0939c4..6d9612fb5 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -2,13 +2,14 @@
// Licensed under GPLv2
// Refer to the license.txt file included.
-#include <algorithm>
+#include <boost/range/algorithm.hpp>
#include "common/common.h"
#include "common/string_util.h"
#ifdef _WIN32
#include <Windows.h>
+ #include <codecvt>
#else
#include <iconv.h>
#endif
@@ -17,20 +18,20 @@ namespace Common {
/// Make a string lowercase
std::string ToLower(std::string str) {
- std::transform(str.begin(), str.end(), str.begin(), ::tolower);
+ boost::transform(str, str.begin(), ::tolower);
return str;
}
/// Make a string uppercase
std::string ToUpper(std::string str) {
- std::transform(str.begin(), str.end(), str.begin(), ::toupper);
+ boost::transform(str, str.begin(), ::toupper);
return str;
}
// faster than sscanf
bool AsciiToHex(const char* _szValue, u32& result)
{
- char *endptr = NULL;
+ char *endptr = nullptr;
const u32 value = strtoul(_szValue, &endptr, 16);
if (!endptr || *endptr)
@@ -68,7 +69,7 @@ bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list ar
// will be present in the middle of a multibyte sequence.
//
// This is why we lookup an ANSI (cp1252) locale here and use _vsnprintf_l.
- static locale_t c_locale = NULL;
+ static locale_t c_locale = nullptr;
if (!c_locale)
c_locale = _create_locale(LC_ALL, ".1252");
writtenCount = _vsnprintf_l(out, outsize, format, c_locale, args);
@@ -91,7 +92,7 @@ bool CharArrayFromFormatV(char* out, int outsize, const char* format, va_list ar
std::string StringFromFormat(const char* format, ...)
{
va_list args;
- char *buf = NULL;
+ char *buf = nullptr;
#ifdef _WIN32
int required = 0;
@@ -106,7 +107,7 @@ std::string StringFromFormat(const char* format, ...)
#else
va_start(args, format);
if (vasprintf(&buf, format, args) < 0)
- ERROR_LOG(COMMON, "Unable to allocate memory for string");
+ LOG_ERROR(Common, "Unable to allocate memory for string");
va_end(args);
std::string temp = buf;
@@ -120,11 +121,11 @@ std::string ArrayToString(const u8 *data, u32 size, int line_len, bool spaces)
{
std::ostringstream oss;
oss << std::setfill('0') << std::hex;
-
+
for (int line = 0; size; ++data, --size)
{
oss << std::setw(2) << (int)*data;
-
+
if (line_len == ++line)
{
oss << '\n';
@@ -161,13 +162,13 @@ std::string StripQuotes(const std::string& s)
bool TryParse(const std::string &str, u32 *const output)
{
- char *endptr = NULL;
+ char *endptr = nullptr;
// Reset errno to a value other than ERANGE
errno = 0;
unsigned long value = strtoul(str.c_str(), &endptr, 0);
-
+
if (!endptr || *endptr)
return false;
@@ -293,7 +294,7 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
//#include <string>
//#include <assert.h>
-const char HEX2DEC[256] =
+const char HEX2DEC[256] =
{
/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
/* 0 */ 16,16,16,16, 16,16,16,16, 16,16,16,16, 16,16,16,16,
@@ -326,7 +327,7 @@ std::string UriDecode(const std::string & sSrc)
const unsigned char * pSrc = (const unsigned char *)sSrc.c_str();
const size_t SRC_LEN = sSrc.length();
const unsigned char * const SRC_END = pSrc + SRC_LEN;
- const unsigned char * const SRC_LAST_DEC = SRC_END - 2; // last decodable '%'
+ const unsigned char * const SRC_LAST_DEC = SRC_END - 2; // last decodable '%'
char * const pStart = new char[SRC_LEN];
char * pEnd = pStart;
@@ -393,7 +394,7 @@ std::string UriEncode(const std::string & sSrc)
for (; pSrc < SRC_END; ++pSrc)
{
- if (SAFE[*pSrc])
+ if (SAFE[*pSrc])
*pEnd++ = *pSrc;
else
{
@@ -411,7 +412,19 @@ std::string UriEncode(const std::string & sSrc)
#ifdef _WIN32
-std::string UTF16ToUTF8(const std::wstring& input)
+std::string UTF16ToUTF8(const std::u16string& input)
+{
+ std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
+ return convert.to_bytes(input);
+}
+
+std::u16string UTF8ToUTF16(const std::string& input)
+{
+ std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> convert;
+ return convert.from_bytes(input);
+}
+
+static std::string UTF16ToUTF8(const std::wstring& input)
{
auto const size = WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), nullptr, 0, nullptr, nullptr);
@@ -424,7 +437,7 @@ std::string UTF16ToUTF8(const std::wstring& input)
return output;
}
-std::wstring CPToUTF16(u32 code_page, const std::string& input)
+static std::wstring CPToUTF16(u32 code_page, const std::string& input)
{
auto const size = MultiByteToWideChar(code_page, 0, input.data(), input.size(), nullptr, 0);
@@ -437,7 +450,7 @@ std::wstring CPToUTF16(u32 code_page, const std::string& input)
return output;
}
-std::wstring UTF8ToUTF16(const std::string& input)
+std::wstring UTF8ToUTF16W(const std::string &input)
{
return CPToUTF16(CP_UTF8, input);
}
@@ -455,61 +468,123 @@ std::string CP1252ToUTF8(const std::string& input)
#else
template <typename T>
-std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input)
+static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& input)
{
std::string result;
iconv_t const conv_desc = iconv_open("UTF-8", fromcode);
- if ((iconv_t)-1 == conv_desc)
+ if ((iconv_t)(-1) == conv_desc)
{
- ERROR_LOG(COMMON, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno));
+ LOG_ERROR(Common, "Iconv initialization failure [%s]: %s", fromcode, strerror(errno));
+ iconv_close(conv_desc);
+ return {};
}
- else
- {
- size_t const in_bytes = sizeof(T) * input.size();
- size_t const out_buffer_size = 4 * in_bytes;
- std::string out_buffer;
- out_buffer.resize(out_buffer_size);
+ const size_t in_bytes = sizeof(T) * input.size();
+ // Multiply by 4, which is the max number of bytes to encode a codepoint
+ const size_t out_buffer_size = 4 * in_bytes;
- auto src_buffer = &input[0];
- size_t src_bytes = in_bytes;
- auto dst_buffer = &out_buffer[0];
- size_t dst_bytes = out_buffer.size();
+ std::string out_buffer;
+ out_buffer.resize(out_buffer_size);
- while (src_bytes != 0)
- {
- size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes,
- &dst_buffer, &dst_bytes);
+ auto src_buffer = &input[0];
+ size_t src_bytes = in_bytes;
+ auto dst_buffer = &out_buffer[0];
+ size_t dst_bytes = out_buffer.size();
- if ((size_t)-1 == iconv_result)
+ while (0 != src_bytes)
+ {
+ size_t const iconv_result = iconv(conv_desc, (char**)(&src_buffer), &src_bytes,
+ &dst_buffer, &dst_bytes);
+
+ if (static_cast<size_t>(-1) == iconv_result)
+ {
+ if (EILSEQ == errno || EINVAL == errno)
{
- if (EILSEQ == errno || EINVAL == errno)
- {
- // Try to skip the bad character
- if (src_bytes != 0)
- {
- --src_bytes;
- ++src_buffer;
- }
- }
- else
+ // Try to skip the bad character
+ if (0 != src_bytes)
{
- ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno));
- break;
+ --src_bytes;
+ ++src_buffer;
}
}
+ else
+ {
+ LOG_ERROR(Common, "iconv failure [%s]: %s", fromcode, strerror(errno));
+ break;
+ }
}
+ }
+
+ out_buffer.resize(out_buffer_size - dst_bytes);
+ out_buffer.swap(result);
+
+ iconv_close(conv_desc);
+
+ return result;
+}
+
+std::u16string UTF8ToUTF16(const std::string& input)
+{
+ std::u16string result;
- out_buffer.resize(out_buffer_size - dst_bytes);
- out_buffer.swap(result);
-
+ iconv_t const conv_desc = iconv_open("UTF-16LE", "UTF-8");
+ if ((iconv_t)(-1) == conv_desc)
+ {
+ LOG_ERROR(Common, "Iconv initialization failure [UTF-8]: %s", strerror(errno));
iconv_close(conv_desc);
+ return {};
}
-
+
+ const size_t in_bytes = sizeof(char) * input.size();
+ // Multiply by 4, which is the max number of bytes to encode a codepoint
+ const size_t out_buffer_size = 4 * sizeof(char16_t) * in_bytes;
+
+ std::u16string out_buffer;
+ out_buffer.resize(out_buffer_size);
+
+ char* src_buffer = const_cast<char*>(&input[0]);
+ size_t src_bytes = in_bytes;
+ char* dst_buffer = (char*)(&out_buffer[0]);
+ size_t dst_bytes = out_buffer.size();
+
+ while (0 != src_bytes)
+ {
+ size_t const iconv_result = iconv(conv_desc, &src_buffer, &src_bytes,
+ &dst_buffer, &dst_bytes);
+
+ if (static_cast<size_t>(-1) == iconv_result)
+ {
+ if (EILSEQ == errno || EINVAL == errno)
+ {
+ // Try to skip the bad character
+ if (0 != src_bytes)
+ {
+ --src_bytes;
+ ++src_buffer;
+ }
+ }
+ else
+ {
+ LOG_ERROR(Common, "iconv failure [UTF-8]: %s", strerror(errno));
+ break;
+ }
+ }
+ }
+
+ out_buffer.resize(out_buffer_size - dst_bytes);
+ out_buffer.swap(result);
+
+ iconv_close(conv_desc);
+
return result;
}
+std::string UTF16ToUTF8(const std::u16string& input)
+{
+ return CodeToUTF8("UTF-16LE", input);
+}
+
std::string CP1252ToUTF8(const std::string& input)
{
//return CodeToUTF8("CP1252//TRANSLIT", input);
@@ -523,19 +598,6 @@ std::string SHIFTJISToUTF8(const std::string& input)
return CodeToUTF8("SJIS", input);
}
-std::string UTF16ToUTF8(const std::wstring& input)
-{
- std::string result =
- // CodeToUTF8("UCS-2", input);
- // CodeToUTF8("UCS-2LE", input);
- // CodeToUTF8("UTF-16", input);
- CodeToUTF8("UTF-16LE", input);
-
- // TODO: why is this needed?
- result.erase(std::remove(result.begin(), result.end(), 0x00), result.end());
- return result;
-}
-
#endif
}
diff --git a/src/common/string_util.h b/src/common/string_util.h
index a41ccc691..7d75691b1 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -63,7 +63,7 @@ template <typename N>
static bool TryParse(const std::string &str, N *const output)
{
std::istringstream iss(str);
-
+
N tmp = 0;
if (iss >> tmp)
{
@@ -89,20 +89,22 @@ std::string ReplaceAll(std::string result, const std::string& src, const std::st
std::string UriDecode(const std::string & sSrc);
std::string UriEncode(const std::string & sSrc);
+std::string UTF16ToUTF8(const std::u16string& input);
+std::u16string UTF8ToUTF16(const std::string& input);
+
std::string CP1252ToUTF8(const std::string& str);
std::string SHIFTJISToUTF8(const std::string& str);
-std::string UTF16ToUTF8(const std::wstring& str);
#ifdef _WIN32
-std::wstring UTF8ToUTF16(const std::string& str);
+std::wstring UTF8ToUTF16W(const std::string& str);
#ifdef _UNICODE
inline std::string TStrToUTF8(const std::wstring& str)
{ return UTF16ToUTF8(str); }
inline std::wstring UTF8ToTStr(const std::string& str)
-{ return UTF8ToUTF16(str); }
+{ return UTF8ToUTF16W(str); }
#else
inline std::string TStrToUTF8(const std::string& str)
{ return str; }
@@ -113,4 +115,19 @@ inline std::string UTF8ToTStr(const std::string& str)
#endif
+/**
+ * Compares the string defined by the range [`begin`, `end`) to the null-terminated C-string
+ * `other` for equality.
+ */
+template <typename InIt>
+bool ComparePartialString(InIt begin, InIt end, const char* other) {
+ for (; begin != end && *other != '\0'; ++begin, ++other) {
+ if (*begin != *other) {
+ return false;
+ }
+ }
+ // Only return true if both strings finished at the same point
+ return (begin == end) == (*other == '\0');
+}
+
}
diff --git a/src/common/symbols.cpp b/src/common/symbols.cpp
index d61f4c0c6..63ad6218b 100644
--- a/src/common/symbols.cpp
+++ b/src/common/symbols.cpp
@@ -31,7 +31,7 @@ namespace Symbols
{
TSymbolsMap::iterator foundSymbolItr;
TSymbol symbol;
-
+
foundSymbolItr = g_symbols.find(_address);
if (foundSymbolItr != g_symbols.end())
{
@@ -44,7 +44,7 @@ namespace Symbols
{
return GetSymbol(_address).name;
}
-
+
void Remove(u32 _address)
{
g_symbols.erase(_address);
diff --git a/src/common/symbols.h b/src/common/symbols.h
index b13a8001a..4560f5240 100644
--- a/src/common/symbols.h
+++ b/src/common/symbols.h
@@ -33,5 +33,5 @@ namespace Symbols
const std::string GetName(u32 _address);
void Remove(u32 _address);
void Clear();
-};
+}
diff --git a/src/common/thread.cpp b/src/common/thread.cpp
index 60d8ed075..dc153ba71 100644
--- a/src/common/thread.cpp
+++ b/src/common/thread.cpp
@@ -25,7 +25,7 @@ int CurrentThreadId()
return 0;
#endif
}
-
+
#ifdef _WIN32
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
@@ -52,7 +52,7 @@ void SwitchCurrentThread()
// Sets the debugger-visible name of the current thread.
// Uses undocumented (actually, it is now documented) trick.
// http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vsdebug/html/vxtsksettingthreadname.asp
-
+
// This is implemented much nicer in upcoming msvc++, see:
// http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx
void SetCurrentThreadName(const char* szThreadName)
@@ -81,7 +81,7 @@ void SetCurrentThreadName(const char* szThreadName)
__except(EXCEPTION_CONTINUE_EXECUTION)
{}
}
-
+
#else // !WIN32, so must be POSIX threads
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask)
diff --git a/src/common/thread.h b/src/common/thread.h
index f7ace21b4..8c36d3f07 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -21,6 +21,7 @@
//for gettimeofday and struct time(spec|val)
#include <time.h>
#include <sys/time.h>
+#include <unistd.h>
#endif
namespace Common
@@ -30,13 +31,13 @@ int CurrentThreadId();
void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask);
void SetCurrentThreadAffinity(u32 mask);
-
+
class Event
{
public:
Event()
: is_set(false)
- {};
+ {}
void Set()
{
@@ -135,7 +136,7 @@ private:
const size_t m_count;
volatile size_t m_waiting;
};
-
+
void SleepCurrentThread(int ms);
void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms
@@ -146,7 +147,7 @@ inline void YieldCPU()
{
std::this_thread::yield();
}
-
+
void SetCurrentThreadName(const char *name);
-
+
} // namespace Common
diff --git a/src/common/thread_queue_list.h b/src/common/thread_queue_list.h
index 4a89572f6..7e3b620c7 100644
--- a/src/common/thread_queue_list.h
+++ b/src/common/thread_queue_list.h
@@ -1,6 +1,6 @@
// Copyright 2014 Citra Emulator Project / PPSSPP Project
// Licensed under GPLv2
-// Refer to the license.txt file included.
+// Refer to the license.txt file included.
#pragma once
@@ -12,7 +12,7 @@ template<class IdType>
struct ThreadQueueList {
// Number of queues (number of priority levels starting at 0.)
static const int NUM_QUEUES = 128;
-
+
// Initial number of threads a single queue can handle.
static const int INITIAL_CAPACITY = 32;
@@ -37,7 +37,7 @@ struct ThreadQueueList {
~ThreadQueueList() {
for (int i = 0; i < NUM_QUEUES; ++i)
{
- if (queues[i].data != NULL)
+ if (queues[i].data != nullptr)
free(queues[i].data);
}
}
@@ -46,7 +46,7 @@ struct ThreadQueueList {
int contains(const IdType uid) {
for (int i = 0; i < NUM_QUEUES; ++i)
{
- if (queues[i].data == NULL)
+ if (queues[i].data == nullptr)
continue;
Queue *cur = &queues[i];
@@ -133,7 +133,7 @@ struct ThreadQueueList {
inline void clear() {
for (int i = 0; i < NUM_QUEUES; ++i)
{
- if (queues[i].data != NULL)
+ if (queues[i].data != nullptr)
free(queues[i].data);
}
memset(queues, 0, sizeof(queues));
@@ -147,7 +147,7 @@ struct ThreadQueueList {
inline void prepare(u32 priority) {
Queue *cur = &queues[priority];
- if (cur->next == NULL)
+ if (cur->next == nullptr)
link(priority, INITIAL_CAPACITY);
}
@@ -176,7 +176,7 @@ private:
for (int i = (int) priority - 1; i >= 0; --i)
{
- if (queues[i].next != NULL)
+ if (queues[i].next != nullptr)
{
cur->next = queues[i].next;
queues[i].next = cur;
@@ -193,7 +193,7 @@ private:
int size = cur->end - cur->first;
if (size >= cur->capacity - 2) {
IdType *new_data = (IdType *)realloc(cur->data, cur->capacity * 2 * sizeof(IdType));
- if (new_data != NULL) {
+ if (new_data != nullptr) {
cur->capacity *= 2;
cur->data = new_data;
}
diff --git a/src/common/timer.cpp b/src/common/timer.cpp
index ded4a344e..4a797f751 100644
--- a/src/common/timer.cpp
+++ b/src/common/timer.cpp
@@ -25,7 +25,7 @@ u32 Timer::GetTimeMs()
return timeGetTime();
#else
struct timeval t;
- (void)gettimeofday(&t, NULL);
+ (void)gettimeofday(&t, nullptr);
return ((u32)(t.tv_sec * 1000 + t.tv_usec / 1000));
#endif
}
@@ -183,7 +183,7 @@ std::string Timer::GetTimeFormatted()
return StringFromFormat("%s:%03i", tmp, tp.millitm);
#else
struct timeval t;
- (void)gettimeofday(&t, NULL);
+ (void)gettimeofday(&t, nullptr);
return StringFromFormat("%s:%03d", tmp, (int)(t.tv_usec / 1000));
#endif
}
@@ -197,7 +197,7 @@ double Timer::GetDoubleTime()
(void)::ftime(&tp);
#else
struct timeval t;
- (void)gettimeofday(&t, NULL);
+ (void)gettimeofday(&t, nullptr);
#endif
// Get continuous timestamp
u64 TmpSeconds = Common::Timer::GetTimeSinceJan1970();
diff --git a/src/common/utf8.cpp b/src/common/utf8.cpp
index be4ebc855..66a2f6339 100644
--- a/src/common/utf8.cpp
+++ b/src/common/utf8.cpp
@@ -281,28 +281,28 @@ int u8_read_escape_sequence(const char *str, u32 *dest)
do {
digs[dno++] = str[i++];
} while (octal_digit(str[i]) && dno < 3);
- ch = strtol(digs, NULL, 8);
+ ch = strtol(digs, nullptr, 8);
}
else if (str[0] == 'x') {
while (hex_digit(str[i]) && dno < 2) {
digs[dno++] = str[i++];
}
if (dno > 0)
- ch = strtol(digs, NULL, 16);
+ ch = strtol(digs, nullptr, 16);
}
else if (str[0] == 'u') {
while (hex_digit(str[i]) && dno < 4) {
digs[dno++] = str[i++];
}
if (dno > 0)
- ch = strtol(digs, NULL, 16);
+ ch = strtol(digs, nullptr, 16);
}
else if (str[0] == 'U') {
while (hex_digit(str[i]) && dno < 8) {
digs[dno++] = str[i++];
}
if (dno > 0)
- ch = strtol(digs, NULL, 16);
+ ch = strtol(digs, nullptr, 16);
}
*dest = ch;
@@ -353,7 +353,7 @@ const char *u8_strchr(const char *s, u32 ch, int *charn)
lasti = i;
(*charn)++;
}
- return NULL;
+ return nullptr;
}
const char *u8_memchr(const char *s, u32 ch, size_t sz, int *charn)
@@ -378,7 +378,7 @@ const char *u8_memchr(const char *s, u32 ch, size_t sz, int *charn)
lasti = i;
(*charn)++;
}
- return NULL;
+ return nullptr;
}
int u8_is_locale_utf8(const char *locale)
@@ -419,35 +419,35 @@ bool UTF8StringHasNonASCII(const char *utf8string) {
std::string ConvertWStringToUTF8(const wchar_t *wstr) {
int len = (int)wcslen(wstr);
- int size = (int)WideCharToMultiByte(CP_UTF8, 0, wstr, len, 0, 0, NULL, NULL);
+ int size = (int)WideCharToMultiByte(CP_UTF8, 0, wstr, len, 0, 0, nullptr, nullptr);
std::string s;
s.resize(size);
if (size > 0) {
- WideCharToMultiByte(CP_UTF8, 0, wstr, len, &s[0], size, NULL, NULL);
+ WideCharToMultiByte(CP_UTF8, 0, wstr, len, &s[0], size, nullptr, nullptr);
}
return s;
}
std::string ConvertWStringToUTF8(const std::wstring &wstr) {
int len = (int)wstr.size();
- int size = (int)WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), len, 0, 0, NULL, NULL);
+ int size = (int)WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), len, 0, 0, nullptr, nullptr);
std::string s;
s.resize(size);
if (size > 0) {
- WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), len, &s[0], size, NULL, NULL);
+ WideCharToMultiByte(CP_UTF8, 0, wstr.c_str(), len, &s[0], size, nullptr, nullptr);
}
return s;
}
void ConvertUTF8ToWString(wchar_t *dest, size_t destSize, const std::string &source) {
int len = (int)source.size();
- int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, NULL, 0);
+ int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, nullptr, 0);
MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, dest, std::min((int)destSize, size));
}
std::wstring ConvertUTF8ToWString(const std::string &source) {
int len = (int)source.size();
- int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, NULL, 0);
+ int size = (int)MultiByteToWideChar(CP_UTF8, 0, source.c_str(), len, nullptr, 0);
std::wstring str;
str.resize(size);
if (size > 0) {