mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 05:40:04 +00:00 
			
		
		
		
	Fix merge conflicts
This commit is contained in:
		
						commit
						8ba9ac0f74
					
				
					 288 changed files with 17413 additions and 13969 deletions
				
			
		|  | @ -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,18 @@ 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 | ||||
|             make_unique.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 | ||||
|  |  | |||
|  | @ -1,4 +1,4 @@ | |||
| // Licensed under GPLv2
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -142,7 +142,7 @@ public: | |||
| 
 | ||||
|     __forceinline BitField& operator=(T val) | ||||
|     { | ||||
|         storage = (storage & ~GetMask()) | (((StorageType)val << position) & GetMask()); | ||||
|         Assign(val); | ||||
|         return *this; | ||||
|     } | ||||
| 
 | ||||
|  | @ -151,6 +151,10 @@ public: | |||
|         return Value(); | ||||
|     } | ||||
| 
 | ||||
|     __forceinline void Assign(const T& value) { | ||||
|         storage = (storage & ~GetMask()) | (((StorageType)value << position) & GetMask()); | ||||
|     } | ||||
| 
 | ||||
|     __forceinline T Value() const | ||||
|     { | ||||
|         if (std::numeric_limits<T>::is_signed) | ||||
|  | @ -164,6 +168,12 @@ public: | |||
|         } | ||||
|     } | ||||
| 
 | ||||
|     // TODO: we may want to change this to explicit operator bool() if it's bug-free in VS2015
 | ||||
|     __forceinline bool ToBool() const | ||||
|     { | ||||
|         return Value() != 0; | ||||
|     } | ||||
| 
 | ||||
| private: | ||||
|     // StorageType is T for non-enum types and the underlying type of T if
 | ||||
|     // T is an enumeration. Note that T is wrapped within an enable_if in the
 | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include "common/common.h" | ||||
|  | @ -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() | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
|  |  | |||
|  | @ -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,7 +198,14 @@ 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; | ||||
|  | @ -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); | ||||
|     } | ||||
| 
 | ||||
|  | @ -369,7 +383,7 @@ public: | |||
|     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,7 +490,7 @@ public: | |||
|             break; | ||||
| 
 | ||||
|         default: | ||||
|             ERROR_LOG(COMMON, "Savestate error: invalid mode %d.", mode); | ||||
|             LOG_ERROR(Common, "Savestate error: invalid mode %d.", mode); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|  | @ -490,7 +504,12 @@ public: | |||
|         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; | ||||
|     } | ||||
|  | @ -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(); | ||||
|         } | ||||
|  | @ -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; | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
|  |  | |||
|  | @ -1,9 +1,12 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include "common_types.h" | ||||
| #include <cstdlib> | ||||
| 
 | ||||
| #ifdef _WIN32 | ||||
| #define SLEEP(x) Sleep(x) | ||||
| #else | ||||
|  | @ -73,6 +76,8 @@ inline u64 _rotr64(u64 x, unsigned int shift){ | |||
| } | ||||
| 
 | ||||
| #else // _MSC_VER
 | ||||
| #include <locale.h> | ||||
| 
 | ||||
| // Function Cross-Compatibility
 | ||||
|     #define strcasecmp _stricmp | ||||
|     #define strncasecmp _strnicmp | ||||
|  | @ -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); | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
|  | @ -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,9 @@ | |||
| #define MAPS_DIR          "maps" | ||||
| #define CACHE_DIR         "cache" | ||||
| #define SDMC_DIR          "sdmc" | ||||
| #define SAVEDATA_DIR      "savedata" | ||||
| #define SYSDATA_DIR       "sysdata" | ||||
| #define SYSSAVEDATA_DIR   "syssavedata" | ||||
| #define SHADERCACHE_DIR   "shader_cache" | ||||
| #define STATESAVES_DIR    "state_saves" | ||||
| #define SCREENSHOTS_DIR   "screenShots" | ||||
|  | @ -70,6 +60,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" | ||||
| 
 | ||||
|  |  | |||
|  | @ -41,8 +41,6 @@ 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)
 | ||||
|  |  | |||
							
								
								
									
										164
									
								
								src/common/concurrent_ring_buffer.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								src/common/concurrent_ring_buffer.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,164 @@ | |||
| // Copyright 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // 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
 | ||||
|  | @ -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 | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
|  | @ -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; | ||||
| }; | ||||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include "emu_window.h" | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
|  |  | |||
|  | @ -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, ";" ); | ||||
|  | @ -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 ); | ||||
| 
 | ||||
|  | @ -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'); | ||||
| 
 | ||||
|  | @ -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; | ||||
|     } | ||||
|  | @ -332,11 +332,11 @@ void StackTrace( HANDLE hThread, const char* lpszMessage, FILE *file ) | |||
|                 hProcess, | ||||
|                 hThread, | ||||
|                 &callStack, | ||||
|                 NULL, | ||||
|                 NULL, | ||||
|                 nullptr, | ||||
|                 nullptr, | ||||
|                 SymFunctionTableAccess, | ||||
|                 SymGetModuleBase, | ||||
|                 NULL); | ||||
|                 nullptr); | ||||
| 
 | ||||
|             if ( index == 0 ) | ||||
|                 continue; | ||||
|  | @ -389,11 +389,11 @@ void StackTrace(HANDLE hThread, const char* lpszMessage, FILE *file, DWORD eip, | |||
|                 hProcess, | ||||
|                 hThread, | ||||
|                 &callStack, | ||||
|                 NULL, | ||||
|                 NULL, | ||||
|                 nullptr, | ||||
|                 nullptr, | ||||
|                 SymFunctionTableAccess, | ||||
|                 SymGetModuleBase, | ||||
|                 NULL); | ||||
|                 nullptr); | ||||
| 
 | ||||
|             if ( index == 0 ) | ||||
|                 continue; | ||||
|  |  | |||
|  | @ -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() | ||||
|         { | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -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
 | ||||
|     // 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,7 +227,7 @@ 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; | ||||
| } | ||||
|  | @ -235,11 +235,11 @@ bool DeleteDir(const std::string &filename) | |||
| // 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; | ||||
| } | ||||
|  | @ -247,13 +247,13 @@ bool Rename(const std::string &srcFilename, const std::string &destFilename) | |||
| // 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,13 +326,13 @@ 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; | ||||
|     } | ||||
| 
 | ||||
|  | @ -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,13 +371,13 @@ 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; | ||||
|     } | ||||
|  | @ -387,11 +387,11 @@ u64 GetSize(FILE *f) | |||
| // 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) | ||||
|  | @ -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; | ||||
|  | @ -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; | ||||
| 
 | ||||
|  | @ -586,11 +586,11 @@ std::string GetCurrentDir() | |||
| { | ||||
|     char *dir; | ||||
|     // Get the current working directory (getcwd uses malloc)
 | ||||
|     if (!(dir = __getcwd(NULL, 0))) { | ||||
|     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); | ||||
|  | @ -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; | ||||
| } | ||||
| 
 | ||||
|  | @ -676,6 +676,9 @@ 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_SYSSAVEDATA_IDX]    = paths[D_USER_IDX] + SYSSAVEDATA_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 +697,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 +720,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_SYSSAVEDATA_IDX]    = paths[D_USER_IDX] + SYSSAVEDATA_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; | ||||
|  | @ -753,19 +758,6 @@ const std::string& GetUserPath(const unsigned int DirIDX, const std::string &new | |||
|     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 +818,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 +826,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 +837,7 @@ IOFile::~IOFile() | |||
| } | ||||
| 
 | ||||
| IOFile::IOFile(IOFile&& other) | ||||
|     : m_file(NULL), m_good(true) | ||||
|     : m_file(nullptr), m_good(true) | ||||
| { | ||||
|     Swap(other); | ||||
| } | ||||
|  | @ -880,14 +872,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; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
|  | @ -27,6 +27,9 @@ enum { | |||
|     D_STATESAVES_IDX, | ||||
|     D_SCREENSHOTS_IDX, | ||||
|     D_SDMC_IDX, | ||||
|     D_SAVEDATA_IDX, | ||||
|     D_SYSDATA_IDX, | ||||
|     D_SYSSAVEDATA_IDX, | ||||
|     D_HIRESTEXTURES_IDX, | ||||
|     D_DUMP_IDX, | ||||
|     D_DUMPFRAMES_IDX, | ||||
|  | @ -202,11 +205,11 @@ public: | |||
|         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; } | ||||
|     operator void*() { return m_good ? m_file : nullptr; } | ||||
| 
 | ||||
|     std::FILE* ReleaseHandle(); | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include "key_map.h" | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
|  | @ -70,7 +70,7 @@ public: | |||
|             // good header, read some key/value pairs
 | ||||
|             K key; | ||||
| 
 | ||||
|             V *value = NULL; | ||||
|             V *value = nullptr; | ||||
|             u32 value_size; | ||||
|             u32 entry_number; | ||||
| 
 | ||||
|  |  | |||
							
								
								
									
										133
									
								
								src/common/log.h
									
										
									
									
									
								
							
							
						
						
									
										133
									
								
								src/common/log.h
									
										
									
									
									
								
							|  | @ -1,108 +1,12 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #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, | ||||
|     GUI, | ||||
| 
 | ||||
|     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 MSVC_VER | ||||
| #ifndef __func__ | ||||
|  | @ -110,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(); | ||||
|  | @ -144,12 +35,12 @@ 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 MSVC_VER | ||||
| #ifdef _WIN32 | ||||
| #define _assert_msg_(_t_, _a_, _fmt_, ...)        \ | ||||
|     if (!(_a_)) {\ | ||||
|         if (!PanicYesNo(_fmt_, __VA_ARGS__)) {Crash();} \ | ||||
|  | @ -159,7 +50,7 @@ void GenericLog(LOGTYPES_LEVELS level, LOGTYPES_TYPE type, const char*file, int | |||
|     if (!(_a_)) {\ | ||||
|         if (!PanicYesNo(_fmt_, ##__VA_ARGS__)) {Crash();} \ | ||||
|     } | ||||
| #endif // MSVC_VER
 | ||||
| #endif // _WIN32
 | ||||
| #else // GEKKO
 | ||||
| #define _assert_msg_(_t_, _a_, _fmt_, ...) | ||||
| #endif | ||||
| #endif | ||||
|  | @ -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" | ||||
| 
 | ||||
| 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_Log[LogTypes::GUI]                = new LogContainer("GUI",               "GUI"); | ||||
| 
 | ||||
|     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 | ||||
| } | ||||
|  | @ -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(); | ||||
| }; | ||||
							
								
								
									
										151
									
								
								src/common/logging/backend.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								src/common/logging/backend.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,151 @@ | |||
| // Copyright 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // 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); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										134
									
								
								src/common/logging/backend.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										134
									
								
								src/common/logging/backend.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,134 @@ | |||
| // Copyright 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // 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(); | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										132
									
								
								src/common/logging/filter.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								src/common/logging/filter.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,132 @@ | |||
| // Copyright 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // 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)]); | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										63
									
								
								src/common/logging/filter.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								src/common/logging/filter.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,63 @@ | |||
| // Copyright 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // 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; | ||||
| }; | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										115
									
								
								src/common/logging/log.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										115
									
								
								src/common/logging/log.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,115 @@ | |||
| // Copyright 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // 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__) | ||||
							
								
								
									
										136
									
								
								src/common/logging/text_formatter.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										136
									
								
								src/common/logging/text_formatter.cpp
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,136 @@ | |||
| // Copyright 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // 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); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										41
									
								
								src/common/logging/text_formatter.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								src/common/logging/text_formatter.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | |||
| // Copyright 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // 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); | ||||
| 
 | ||||
| } | ||||
							
								
								
									
										16
									
								
								src/common/make_unique.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								src/common/make_unique.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,16 @@ | |||
| // Copyright 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
| 
 | ||||
| #include <memory> | ||||
| 
 | ||||
| namespace Common { | ||||
| 
 | ||||
| template <typename T, typename... Args> | ||||
| std::unique_ptr<T> make_unique(Args&&... args) { | ||||
|     return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); | ||||
| } | ||||
| 
 | ||||
| } // namespace
 | ||||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
|  |  | |||
|  | @ -30,7 +30,7 @@ | |||
| #endif | ||||
| 
 | ||||
| #ifdef IOS | ||||
| void* globalbase = NULL; | ||||
| void* globalbase = nullptr; | ||||
| #endif | ||||
| 
 | ||||
| #ifdef ANDROID | ||||
|  | @ -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) { | ||||
|  | @ -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; | ||||
|     } | ||||
| } | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| 
 | ||||
|  | @ -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; | ||||
|  | @ -130,7 +130,7 @@ void FreeMemoryPages(void* ptr, size_t size) | |||
| 
 | ||||
|         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); | ||||
|  | @ -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()); | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include "common/common.h" | ||||
|  | @ -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] = {}; | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <cstdio> | ||||
|  | @ -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)) | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
|  |  | |||
|  | @ -80,7 +80,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; | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
|  |  | |||
							
								
								
									
										37
									
								
								src/common/scope_exit.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								src/common/scope_exit.h
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,37 @@ | |||
| // Copyright 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // 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) | ||||
|  | @ -1,8 +1,8 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <algorithm> | ||||
| #include <boost/range/algorithm.hpp> | ||||
| 
 | ||||
| #include "common/common.h" | ||||
| #include "common/string_util.h" | ||||
|  | @ -18,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) | ||||
|  | @ -69,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); | ||||
|  | @ -92,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; | ||||
| 
 | ||||
|  | @ -107,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; | ||||
|  | @ -162,7 +162,7 @@ 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; | ||||
|  | @ -475,7 +475,7 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& | |||
|     iconv_t const conv_desc = iconv_open("UTF-8", fromcode); | ||||
|     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 {}; | ||||
|     } | ||||
|  | @ -510,7 +510,7 @@ static std::string CodeToUTF8(const char* fromcode, const std::basic_string<T>& | |||
|             } | ||||
|             else | ||||
|             { | ||||
|                 ERROR_LOG(COMMON, "iconv failure [%s]: %s", fromcode, strerror(errno)); | ||||
|                 LOG_ERROR(Common, "iconv failure [%s]: %s", fromcode, strerror(errno)); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | @ -528,10 +528,10 @@ std::u16string UTF8ToUTF16(const std::string& input) | |||
| { | ||||
|     std::u16string result; | ||||
| 
 | ||||
|     iconv_t const conv_desc = iconv_open("UTF-16", "UTF-8"); | ||||
|     iconv_t const conv_desc = iconv_open("UTF-16LE", "UTF-8"); | ||||
|     if ((iconv_t)(-1) == conv_desc) | ||||
|     { | ||||
|         ERROR_LOG(COMMON, "Iconv initialization failure [UTF-8]: %s", strerror(errno)); | ||||
|         LOG_ERROR(Common, "Iconv initialization failure [UTF-8]: %s", strerror(errno)); | ||||
|         iconv_close(conv_desc); | ||||
|         return {}; | ||||
|     } | ||||
|  | @ -566,7 +566,7 @@ std::u16string UTF8ToUTF16(const std::string& input) | |||
|             } | ||||
|             else | ||||
|             { | ||||
|                 ERROR_LOG(COMMON, "iconv failure [UTF-8]: %s", strerror(errno)); | ||||
|                 LOG_ERROR(Common, "iconv failure [UTF-8]: %s", strerror(errno)); | ||||
|                 break; | ||||
|             } | ||||
|         } | ||||
|  | @ -582,7 +582,7 @@ std::u16string UTF8ToUTF16(const std::string& input) | |||
| 
 | ||||
| std::string UTF16ToUTF8(const std::u16string& input) | ||||
| { | ||||
|     return CodeToUTF8("UTF-16", input); | ||||
|     return CodeToUTF8("UTF-16LE", input); | ||||
| } | ||||
| 
 | ||||
| std::string CP1252ToUTF8(const std::string& input) | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
|  | @ -115,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'); | ||||
| } | ||||
| 
 | ||||
| } | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include "common/symbols.h" | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include "common/thread.h" | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
|  | @ -21,6 +21,7 @@ | |||
| //for gettimeofday and struct time(spec|val)
 | ||||
| #include <time.h> | ||||
| #include <sys/time.h> | ||||
| #include <unistd.h> | ||||
| #endif | ||||
| 
 | ||||
| namespace Common | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2014 Citra Emulator Project / PPSSPP Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
|  | @ -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; | ||||
|             } | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #include <time.h> | ||||
|  | @ -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(); | ||||
|  |  | |||
|  | @ -1,5 +1,5 @@ | |||
| // Copyright 2013 Dolphin Emulator Project
 | ||||
| // Licensed under GPLv2
 | ||||
| // Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
 | ||||
| // Licensed under GPLv2 or any later version
 | ||||
| // Refer to the license.txt file included.
 | ||||
| 
 | ||||
| #pragma once | ||||
|  |  | |||
|  | @ -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) { | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue