From 4e90906b04be67591bf7632c882d09f7bc5f00c3 Mon Sep 17 00:00:00 2001 From: omar Date: Tue, 19 Nov 2019 21:14:44 +0100 Subject: [PATCH] Added IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS / IMGUI_DISABLE_FILE_FUNCTIONS #2734) Using in Emscripten example. --- docs/CHANGELOG.txt | 2 + examples/example_emscripten/Makefile | 2 +- imconfig.h | 1 + imgui.cpp | 79 +++++++++++++++++++--------- imgui_demo.cpp | 6 +++ imgui_internal.h | 30 +++++++++-- 6 files changed, 91 insertions(+), 29 deletions(-) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 37382268..014e7c67 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -81,6 +81,8 @@ Other Changes: - Misc: Windows: Do not use _wfopen() if IMGUI_DISABLE_WIN32_FUNCTIONS is defined. (#2815) - Misc: Windows: Disabled win32 function by default when building with UWP. (#2892, #2895) - Misc: Using static_assert() when using C++11, instead of our own construct (avoid zealous Clang warnings). +- Misc: Added IMGUI_DISABLE_FILE_FUNCTIONS/IMGUI_DISABLE_DEFAULT_FILE_FUNCTION to nullify or disable + default implementationof ImFileXXX functions linking with fopen/fclose/fread/fwrite. (#2734) - Docs: Improved and moved FAQ to docs/FAQ.md so it can be readable on the web. [@ButternCream, @ocornut] - Docs: Added permanent redirect from https://www.dearimgui.org/faq to FAQ page. - Demo: Added simple item reordering demo in Widgets -> Drag and Drop section. (#2823, #143) [@rokups] diff --git a/examples/example_emscripten/Makefile b/examples/example_emscripten/Makefile index 480fabd7..f5b7369a 100644 --- a/examples/example_emscripten/Makefile +++ b/examples/example_emscripten/Makefile @@ -25,9 +25,9 @@ EMS = -s USE_SDL=2 -s WASM=1 EMS += -s ALLOW_MEMORY_GROWTH=1 EMS += -s DISABLE_EXCEPTION_CATCHING=1 -s NO_EXIT_RUNTIME=0 EMS += -s ASSERTIONS=1 +EMS += -s NO_FILESYSTEM=1 -DIMGUI_DISABLE_FILE_FUNCTIONS # Uncomment next line to fix possible rendering bugs with emscripten version older then 1.39.0 (https://github.com/ocornut/imgui/issues/2877) #EMS += -s BINARYEN_TRAP_MODE=clamp -#EMS += -s NO_FILESYSTEM=1 ## Getting "error: undefined symbol: $FS" if filesystem is removed #EMS += -s SAFE_HEAP=1 ## Adds overhead CPPFLAGS = -I../ -I../../ diff --git a/imconfig.h b/imconfig.h index 97194541..9e0c1451 100644 --- a/imconfig.h +++ b/imconfig.h @@ -37,6 +37,7 @@ //#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default). //#define IMGUI_DISABLE_DEFAULT_FORMAT_STRING_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf) //#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself. +//#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite so you can implement them yourself if you don't want to link with fopen/fclose/fread/fwrite. This will also disable the LogToTTY() function. //#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions(). //---- Include imgui_user.h at the end of imgui.h as a convenience diff --git a/imgui.cpp b/imgui.cpp index b5da86a4..ef23e1b4 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -46,6 +46,7 @@ CODE // [SECTION] CONTEXT AND MEMORY ALLOCATORS // [SECTION] MAIN USER FACING STRUCTURES (ImGuiStyle, ImGuiIO) // [SECTION] MISC HELPERS/UTILITIES (Maths, String, Format, Hash, File functions) +// [SECTION] MISC HELPERS/UTILITIES (File functions) // [SECTION] MISC HELPERS/UTILITIES (ImText* functions) // [SECTION] MISC HELPERS/UTILITIES (Color functions) // [SECTION] ImGuiStorage @@ -1369,10 +1370,16 @@ ImU32 ImHashStr(const char* data_p, size_t data_size, ImU32 seed) return ~crc; } -FILE* ImFileOpen(const char* filename, const char* mode) +//----------------------------------------------------------------------------- +// [SECTION] MISC HELPERS/UTILITIES (File functions) +//----------------------------------------------------------------------------- + +// Default file functions +#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS +ImFileHandle ImFileOpen(const char* filename, const char* mode) { #if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(__CYGWIN__) && !defined(__GNUC__) - // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. Converting both strings from UTF-8 to wchar format (using a single allocation, because we can) + // We need a fopen() wrapper because MSVC/Windows fopen doesn't handle UTF-8 filenames. const int filename_wsize = ImTextCountCharsFromUtf8(filename, NULL) + 1; const int mode_wsize = ImTextCountCharsFromUtf8(mode, NULL) + 1; ImVector buf; @@ -1384,43 +1391,47 @@ FILE* ImFileOpen(const char* filename, const char* mode) return fopen(filename, mode); #endif } +int ImFileClose(ImFileHandle f) { return fclose(f); } +size_t ImFileGetSize(ImFileHandle f) { long off = 0, sz = 0; return ((off = ftell(f)) != -1 && !fseek(f, 0, SEEK_END) && (sz = ftell(f)) != -1 && !fseek(f, off, SEEK_SET)) ? (size_t)sz : (size_t)-1; } +size_t ImFileRead(void* data, size_t sz, size_t count, ImFileHandle f) { return fread(data, sz, count, f); } +size_t ImFileWrite(const void* data, size_t sz, size_t count, ImFileHandle f) { return fwrite(data, sz, count, f); } +#endif // #ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS -// Load file content into memory +// Helper: Load file content into memory // Memory allocated with IM_ALLOC(), must be freed by user using IM_FREE() == ImGui::MemFree() -void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size, int padding_bytes) +void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size, int padding_bytes) { - IM_ASSERT(filename && file_open_mode); + IM_ASSERT(filename && mode); if (out_file_size) *out_file_size = 0; - FILE* f; - if ((f = ImFileOpen(filename, file_open_mode)) == NULL) + ImFileHandle f; + if ((f = ImFileOpen(filename, mode)) == NULL) return NULL; - long file_size_signed; - if (fseek(f, 0, SEEK_END) || (file_size_signed = ftell(f)) == -1 || fseek(f, 0, SEEK_SET)) + size_t file_size = ImFileGetSize(f); + if (file_size == (size_t)-1) { - fclose(f); + ImFileClose(f); return NULL; } - size_t file_size = (size_t)file_size_signed; void* file_data = IM_ALLOC(file_size + padding_bytes); if (file_data == NULL) { - fclose(f); + ImFileClose(f); return NULL; } - if (fread(file_data, 1, file_size, f) != file_size) + if (ImFileRead(file_data, 1, file_size, f) != file_size) { - fclose(f); + ImFileClose(f); IM_FREE(file_data); return NULL; } if (padding_bytes > 0) memset((void*)(((char*)file_data) + file_size), 0, (size_t)padding_bytes); - fclose(f); + ImFileClose(f); if (out_file_size) *out_file_size = file_size; @@ -3822,9 +3833,12 @@ void ImGui::Shutdown(ImGuiContext* context) g.SettingsWindows.clear(); g.SettingsHandlers.clear(); - if (g.LogFile && g.LogFile != stdout) + if (g.LogFile) { - fclose(g.LogFile); +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS + if (g.LogFile != stdout) +#endif + ImFileClose(g.LogFile); g.LogFile = NULL; } g.LogBuffer.clear(); @@ -9055,9 +9069,15 @@ void ImGui::LogText(const char* fmt, ...) va_list args; va_start(args, fmt); if (g.LogFile) - vfprintf(g.LogFile, fmt, args); - else + { + g.LogBuffer.Buf.resize(0); g.LogBuffer.appendfv(fmt, args); + ImFileWrite(g.LogBuffer.c_str(), sizeof(char), (size_t)g.LogBuffer.size(), g.LogFile); + } + else + { + g.LogBuffer.appendfv(fmt, args); + } va_end(args); } @@ -9134,8 +9154,11 @@ void ImGui::LogToTTY(int auto_open_depth) ImGuiContext& g = *GImGui; if (g.LogEnabled) return; + IM_UNUSED(auto_open_depth); +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS LogBegin(ImGuiLogType_TTY, auto_open_depth); g.LogFile = stdout; +#endif } // Start logging/capturing text output to given file @@ -9152,8 +9175,8 @@ void ImGui::LogToFile(int auto_open_depth, const char* filename) filename = g.IO.LogFilename; if (!filename || !filename[0]) return; - FILE* f = ImFileOpen(filename, "ab"); - if (f == NULL) + ImFileHandle f = ImFileOpen(filename, "ab"); + if (!f) { IM_ASSERT(0); return; @@ -9190,10 +9213,12 @@ void ImGui::LogFinish() switch (g.LogType) { case ImGuiLogType_TTY: +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS fflush(g.LogFile); +#endif break; case ImGuiLogType_File: - fclose(g.LogFile); + ImFileClose(g.LogFile); break; case ImGuiLogType_Buffer: break; @@ -9219,7 +9244,11 @@ void ImGui::LogButtons() ImGuiContext& g = *GImGui; PushID("LogButtons"); +#ifndef IMGUI_DISABLE_TTY_FUNCTIONS const bool log_to_tty = Button("Log To TTY"); SameLine(); +#else + const bool log_to_tty = false; +#endif const bool log_to_file = Button("Log To File"); SameLine(); const bool log_to_clipboard = Button("Log To Clipboard"); SameLine(); PushAllowKeyboardFocus(false); @@ -9379,11 +9408,11 @@ void ImGui::SaveIniSettingsToDisk(const char* ini_filename) size_t ini_data_size = 0; const char* ini_data = SaveIniSettingsToMemory(&ini_data_size); - FILE* f = ImFileOpen(ini_filename, "wt"); + ImFileHandle f = ImFileOpen(ini_filename, "wt"); if (!f) return; - fwrite(ini_data, sizeof(char), ini_data_size, f); - fclose(f); + ImFileWrite(ini_data, sizeof(char), ini_data_size, f); + ImFileClose(f); } // Call registered handlers (e.g. SettingsHandlerWindow_WriteAll() + custom handlers) to write their stuff into a text buffer diff --git a/imgui_demo.cpp b/imgui_demo.cpp index e45756f1..d451451b 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3112,6 +3112,12 @@ void ImGui::ShowAboutWindow(bool* p_open) #ifdef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS ImGui::Text("define: IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS"); #endif +#ifdef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS"); +#endif +#ifdef IMGUI_DISABLE_FILE_FUNCTIONS + ImGui::Text("define: IMGUI_DISABLE_FILE_FUNCTIONS"); +#endif #ifdef IMGUI_DISABLE_DEFAULT_ALLOCATORS ImGui::Text("define: IMGUI_DISABLE_DEFAULT_ALLOCATORS"); #endif diff --git a/imgui_internal.h b/imgui_internal.h index 2696e748..9d29cb2a 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -191,8 +191,6 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer #endif // Helpers: Misc -IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size = NULL, int padding_bytes = 0); -IMGUI_API FILE* ImFileOpen(const char* filename, const char* file_open_mode); #define ImQsort qsort IMGUI_API ImU32 ImHashData(const void* data, size_t data_size, ImU32 seed = 0); IMGUI_API ImU32 ImHashStr(const char* data, size_t data_size = 0, ImU32 seed = 0); @@ -260,6 +258,32 @@ static inline ImVec4 operator-(const ImVec4& lhs, const ImVec4& rhs) static inline ImVec4 operator*(const ImVec4& lhs, const ImVec4& rhs) { return ImVec4(lhs.x*rhs.x, lhs.y*rhs.y, lhs.z*rhs.z, lhs.w*rhs.w); } #endif +// Helpers: File System +#if defined(__EMSCRIPTEN__) && !defined(IMGUI_DISABLE_FILE_FUNCTIONS) +#define IMGUI_DISABLE_FILE_FUNCTIONS +#endif +#ifdef IMGUI_DISABLE_FILE_FUNCTIONS +#define IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS +typedef void* ImFileHandle; +static inline ImFileHandle ImFileOpen(const char*, const char*) { return NULL; } +static inline int ImFileClose(ImFileHandle) { return -1; } +static inline size_t ImFileGetSize(ImFileHandle) { return (size_t)-1; } +static inline size_t ImFileRead(void*, size_t, size_t, ImFileHandle) { return 0; } +static inline size_t ImFileWrite(const void*, size_t, size_t, ImFileHandle) { return 0; } +#endif + +#ifndef IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS +typedef FILE* ImFileHandle; +IMGUI_API ImFileHandle ImFileOpen(const char* filename, const char* mode); +IMGUI_API int ImFileClose(ImFileHandle file); +IMGUI_API size_t ImFileGetSize(ImFileHandle file); +IMGUI_API size_t ImFileRead(void* data, size_t size, size_t count, ImFileHandle file); +IMGUI_API size_t ImFileWrite(const void* data, size_t size, size_t count, ImFileHandle file); +#else +#define IMGUI_DISABLE_TTY_FUNCTIONS // Can't use stdout, fflush if we are not using default file functions +#endif +IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* mode, size_t* out_file_size = NULL, int padding_bytes = 0); + // Helpers: Maths // - Wrapper for standard libs functions. (Note that imgui_demo.cpp does _not_ use them to keep the code easy to copy) #ifndef IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS @@ -1103,7 +1127,7 @@ struct ImGuiContext // Capture/Logging bool LogEnabled; ImGuiLogType LogType; - FILE* LogFile; // If != NULL log to stdout/ file + ImFileHandle LogFile; // If != NULL log to stdout/ file ImGuiTextBuffer LogBuffer; // Accumulation buffer when log to clipboard. This is pointer so our GImGui static constructor doesn't call heap allocators. float LogLinePosY; bool LogLineFirstItem;