From 7357b6ed57d055e7a0679cead4b4d09178d26a2f Mon Sep 17 00:00:00 2001 From: Garux Date: Wed, 4 Dec 2024 06:20:37 +0500 Subject: [PATCH] rewrite ini reader/writer --- Makefile | 8 -- contrib/prtview/prtview.cpp | 200 ++++++++++++++++++------------------ contrib/prtview/prtview.h | 6 -- libs/profile/profile2.h | 117 +++++++++++++++++++++ libs/stream/stringstream.h | 6 ++ radiant/commands.cpp | 32 ++---- 6 files changed, 235 insertions(+), 134 deletions(-) create mode 100644 libs/profile/profile2.h diff --git a/Makefile b/Makefile index 54c1a3a8..f3d2fe79 100644 --- a/Makefile +++ b/Makefile @@ -930,7 +930,6 @@ $(INSTALLDIR)/radiant.$(EXE): \ libcommandlib.$(A) \ libgtkutil.$(A) \ libl_net.$(A) \ - libprofile.$(A) \ libquickhull.$(A) \ libxmllib.$(A) \ $(if $(findstring Win32,$(OS)),icons/radiant.o,) \ @@ -943,11 +942,6 @@ libcommandlib.$(A): CPPFLAGS_EXTRA := -Ilibs libcommandlib.$(A): \ libs/commandlib.o \ -libprofile.$(A): CPPFLAGS_EXTRA := -Ilibs -Iinclude -libprofile.$(A): \ - libs/profile/file.o \ - libs/profile/profile.o \ - libgtkutil.$(A): CPPFLAGS_EXTRA := $(CPPFLAGS_GLIB) $(CPPFLAGS_QTWIDGETS) -Ilibs -Iinclude libgtkutil.$(A): \ libs/gtkutil/accelerator.o \ @@ -1120,7 +1114,6 @@ $(INSTALLDIR)/plugins/bobtoolz.$(DLL): \ contrib/bobtoolz/visfind.o \ libcommandlib.$(A) \ libmathlib.$(A) \ - libprofile.$(A) \ $(INSTALLDIR)/plugins/brushexport.$(DLL): LIBS_EXTRA := $(LIBS_GLIB) $(LIBS_QTWIDGETS) $(INSTALLDIR)/plugins/brushexport.$(DLL): CPPFLAGS_EXTRA := $(CPPFLAGS_GLIB) $(CPPFLAGS_QTWIDGETS) -Ilibs -Iinclude @@ -1138,7 +1131,6 @@ $(INSTALLDIR)/plugins/prtview.$(DLL): \ contrib/prtview/LoadPortalFileDialog.o \ contrib/prtview/portals.o \ contrib/prtview/prtview.o \ - libprofile.$(A) \ $(INSTALLDIR)/plugins/shaderplug.$(DLL): LIBS_EXTRA := $(LIBS_GLIB) $(LIBS_QTWIDGETS) $(LIBS_XML) $(INSTALLDIR)/plugins/shaderplug.$(DLL): CPPFLAGS_EXTRA := $(CPPFLAGS_GLIB) $(CPPFLAGS_QTWIDGETS) $(CPPFLAGS_XML) -Ilibs -Iinclude diff --git a/contrib/prtview/prtview.cpp b/contrib/prtview/prtview.cpp index a08a692b..6a35f296 100644 --- a/contrib/prtview/prtview.cpp +++ b/contrib/prtview/prtview.cpp @@ -22,7 +22,7 @@ #include #include -#include "profile/profile.h" +#include "profile/profile2.h" #include "qerplugin.h" #include "iscenegraph.h" @@ -36,122 +36,127 @@ #include "LoadPortalFileDialog.h" #define Q3R_CMD_SPLITTER "-" -#define Q3R_CMD_ABOUT "About Portal Viewer" -#define Q3R_CMD_LOAD "Load .prt file" -#define Q3R_CMD_RELEASE "Unload .prt file" -#define Q3R_CMD_SHOW_3D "Toggle portals (3D)" -#define Q3R_CMD_SHOW_2D "Toggle portals (2D)" -#define Q3R_CMD_OPTIONS "Configure Portal Viewer" - -CopiedString INIfn; +#define Q3R_CMD_ABOUT "About Portal Viewer" +#define Q3R_CMD_LOAD "Load .prt file" +#define Q3R_CMD_RELEASE "Unload .prt file" +#define Q3R_CMD_SHOW_3D "Toggle portals (3D)" +#define Q3R_CMD_SHOW_2D "Toggle portals (2D)" +#define Q3R_CMD_OPTIONS "Configure Portal Viewer" ///////////////////////////////////////////////////////////////////////////// // CPrtViewApp construction -const char RENDER_2D[] = "Render2D"; -const char WIDTH_2D[] = "Width2D"; -const char COLOR_2D[] = "Color2D"; +const char RENDER_2D [] = "Render2D"; +const char WIDTH_2D [] = "Width2D"; +const char COLOR_2D [] = "Color2D"; -const char DRAW_HINTS[] = "DrawHints"; +const char DRAW_HINTS [] = "DrawHints"; const char DRAW_NONHINTS[] = "DrawNonHints"; -const char RENDER_3D[] = "Render3D"; -const char WIDTH_3D[] = "Width3D"; -const char COLOR_3D[] = "Color3D"; -const char COLOR_FOG[] = "ColorFog"; -const char FOG[] = "Fog"; -const char ZBUFFER[] = "ZBuffer"; -const char POLYGON[] = "Polygons"; -const char LINE[] = "Lines"; -const char OPACITY_3D[] = "Opacity"; -const char CLIP_RANGE[] = "ClipRange"; -const char CLIP[] = "Clip"; +const char RENDER_3D [] = "Render3D"; +const char ZBUFFER [] = "ZBuffer"; +const char FOG [] = "Fog"; +const char POLYGON [] = "Polygons"; +const char LINE [] = "Lines"; +const char WIDTH_3D [] = "Width3D"; +const char COLOR_3D [] = "Color3D"; +const char COLOR_FOG [] = "ColorFog"; +const char OPACITY_3D [] = "Opacity"; +const char CLIP [] = "Clip"; +const char CLIP_RANGE [] = "ClipRange"; +class PrtViewIniFile +{ + IniFile m_ini; + StringOutputStream INI_path() const { + return StringStream( GlobalRadiant().getSettingsPath(), "prtview.ini" ); + } + static constexpr char CONFIG_SECTION[] = "Configuration"; +public: + void read(){ + m_ini.read( INI_path() ); + } + void write() const { + m_ini.write( INI_path() ); + } + int GetInt( const char *key, int def ) const { + const auto value = m_ini.getValue( CONFIG_SECTION, key ); + return value? atoi( *value ) : def; + } + void SetInt( const char *key, int val, const char *comment ){ + char s[512]; + snprintf( s, std::size( s ), "%d ; %s", val, comment ); + m_ini.setValue( CONFIG_SECTION, key, s ); + } +}; -void PrtView_construct(){ - INIfn = StringStream( GlobalRadiant().getSettingsPath(), "prtview.ini" ); +void LoadConfig(){ + PrtViewIniFile ini; + ini.read(); - portals.show_2d = INIGetInt( RENDER_2D, 0 ); - portals.width_2d = std::clamp( INIGetInt( WIDTH_2D, 3 ), 1, 10 ); - portals.color_2d = INIGetInt( COLOR_2D, RGB_PACK( 0, 0, 255 ) ) & 0xFFFFFF; + portals.show_2d = ini.GetInt( RENDER_2D , 0 ); + portals.width_2d = std::clamp( ini.GetInt( WIDTH_2D , 3 ), 1, 10 ); + portals.color_2d = ini.GetInt( COLOR_2D , RGB_PACK( 0, 0, 255 ) ) & 0xFFFFFF; - portals.draw_hints = INIGetInt( DRAW_HINTS, 1 ); - portals.draw_nonhints = INIGetInt( DRAW_NONHINTS, 1 ); + portals.draw_hints = ini.GetInt( DRAW_HINTS , 1 ); + portals.draw_nonhints = ini.GetInt( DRAW_NONHINTS, 1 ); - portals.show_3d = INIGetInt( RENDER_3D, 1 ); - - portals.zbuffer = INIGetInt( ZBUFFER, 1 ); - portals.fog = INIGetInt( FOG, 0 ); - portals.polygons = INIGetInt( POLYGON, 1 ); - portals.lines = INIGetInt( LINE, 1 ); - portals.width_3d = std::clamp( INIGetInt( WIDTH_3D, 3 ), 1, 10 ); - portals.color_3d = INIGetInt( COLOR_3D, RGB_PACK( 255, 255, 0 ) ) & 0xFFFFFF; - portals.color_fog = INIGetInt( COLOR_FOG, RGB_PACK( 127, 127, 127 ) ) & 0xFFFFFF; - portals.opacity_3d = std::clamp( INIGetInt( OPACITY_3D, 50 ), 0, 100 ); - portals.clip = INIGetInt( CLIP, 0 ); - portals.clip_range = std::clamp( INIGetInt( CLIP_RANGE, 1024 ), 64, 8192 ); + portals.show_3d = ini.GetInt( RENDER_3D , 1 ); + portals.zbuffer = ini.GetInt( ZBUFFER , 1 ); + portals.fog = ini.GetInt( FOG , 0 ); + portals.polygons = ini.GetInt( POLYGON , 1 ); + portals.lines = ini.GetInt( LINE , 1 ); + portals.width_3d = std::clamp( ini.GetInt( WIDTH_3D , 3 ), 1, 10 ); + portals.color_3d = ini.GetInt( COLOR_3D , RGB_PACK( 255, 255, 0 ) ) & 0xFFFFFF; + portals.color_fog = ini.GetInt( COLOR_FOG , RGB_PACK( 127, 127, 127 ) ) & 0xFFFFFF; + portals.opacity_3d = std::clamp( ini.GetInt( OPACITY_3D , 50 ), 0, 100 ); + portals.clip = ini.GetInt( CLIP , 0 ); + portals.clip_range = std::clamp( ini.GetInt( CLIP_RANGE , 1024 ), 64, 8192 ); if ( portals.zbuffer < 0 || portals.zbuffer > 2 ) portals.zbuffer = 0; - - SaveConfig(); - portals.FixColors(); +} +void SaveConfig(){ + PrtViewIniFile ini; + + ini.SetInt( RENDER_2D, portals.show_2d, "Draw in 2D windows" ); + ini.SetInt( WIDTH_2D, portals.width_2d, "Width of lines in 2D windows" ); + ini.SetInt( COLOR_2D, portals.color_2d, "Color of lines in 2D windows" ); + + ini.SetInt( DRAW_HINTS, portals.draw_hints, "Draw Hint Portals" ); + ini.SetInt( DRAW_NONHINTS, portals.draw_nonhints, "Draw Regular Portals" ); + + ini.SetInt( RENDER_3D, portals.show_3d, "Draw in 3D windows" ); + ini.SetInt( ZBUFFER, portals.zbuffer, "ZBuffer level in 3D window" ); + ini.SetInt( FOG, portals.fog, "Use depth cueing in 3D window" ); + ini.SetInt( POLYGON, portals.polygons, "Render using polygons in 3D window" ); + ini.SetInt( LINE, portals.lines, "Render using lines in 3D window" ); + ini.SetInt( WIDTH_3D, portals.width_3d, "Width of lines in 3D window" ); + ini.SetInt( COLOR_3D, portals.color_3d, "Color of lines/polygons in 3D window" ); + ini.SetInt( COLOR_FOG, portals.color_fog, "Color of distant lines/polygons in 3D window" ); + ini.SetInt( OPACITY_3D, portals.opacity_3d, "Opacity in 3d view (0 = invisible, 100 = solid)" ); + ini.SetInt( CLIP, portals.clip, "Cubic clipper active for portal viewer" ); + ini.SetInt( CLIP_RANGE, portals.clip_range, "Portal viewer cubic clip distance (in units of 64)" ); + + ini.write(); +} + + +void PrtView_construct(){ + LoadConfig(); Portals_constructShaders(); GlobalShaderCache().attachRenderable( render ); } void PrtView_destroy(){ + SaveConfig(); GlobalShaderCache().detachRenderable( render ); Portals_destroyShaders(); } -void SaveConfig(){ - INISetInt( RENDER_2D, portals.show_2d, "Draw in 2D windows" ); - INISetInt( WIDTH_2D, portals.width_2d, "Width of lines in 2D windows" ); - INISetInt( COLOR_2D, portals.color_2d, "Color of lines in 2D windows" ); - - INISetInt( ZBUFFER, portals.zbuffer, "ZBuffer level in 3D window" ); - INISetInt( FOG, portals.fog, "Use depth cueing in 3D window" ); - INISetInt( POLYGON, portals.polygons, "Render using polygons in 3D window" ); - INISetInt( LINE, portals.lines, "Render using lines in 3D window" ); - INISetInt( RENDER_3D, portals.show_3d, "Draw in 3D windows" ); - INISetInt( WIDTH_3D, portals.width_3d, "Width of lines in 3D window" ); - INISetInt( COLOR_3D, portals.color_3d, "Color of lines/polygons in 3D window" ); - INISetInt( COLOR_FOG, portals.color_fog, "Color of distant lines/polygons in 3D window" ); - INISetInt( OPACITY_3D, portals.opacity_3d, "Opacity in 3d view (0 = invisible, 100 = solid)" ); - INISetInt( CLIP, portals.clip, "Cubic clipper active for portal viewer" ); - INISetInt( CLIP_RANGE, portals.clip_range, "Portal viewer cubic clip distance (in units of 64)" ); -} - - -const char CONFIG_SECTION[] = "Configuration"; - -int INIGetInt( const char *key, int def ){ - char value[1024]; - - if ( read_var( INIfn.c_str(), CONFIG_SECTION, key, value ) ) { - return atoi( value ); - } - else{ - return def; - } -} - -void INISetInt( const char *key, int val, const char *comment /* = NULL */ ){ - char s[1000]; - - if ( comment ) { - sprintf( s, "%d ; %s", val, comment ); - } - else{ - sprintf( s, "%d", val ); - } - save_var( INIfn.c_str(), CONFIG_SECTION, key, s ); -} - // plugin name static const char *PLUGIN_NAME = "Portal Viewer"; @@ -192,10 +197,10 @@ const char* QERPlug_GetCommandTitleList(){ void QERPlug_Dispatch( const char* p, float* vMin, float* vMax, bool bSingleBrush ){ globalOutputStream() << MSG_PREFIX "Command \"" << p << "\"\n"; - if ( !strcmp( p,Q3R_CMD_ABOUT ) ) { + if ( !strcmp( p, Q3R_CMD_ABOUT ) ) { DoAboutDlg(); } - else if ( !strcmp( p,Q3R_CMD_LOAD ) ) { + else if ( !strcmp( p, Q3R_CMD_LOAD ) ) { if ( DoLoadPortalFileDialog() ) { portals.Load(); SceneChangeNotify(); @@ -205,18 +210,17 @@ void QERPlug_Dispatch( const char* p, float* vMin, float* vMax, bool bSingleBrus globalOutputStream() << MSG_PREFIX "Portal file load aborted.\n"; } } - else if ( !strcmp( p,Q3R_CMD_RELEASE ) ) { + else if ( !strcmp( p, Q3R_CMD_RELEASE ) ) { portals.Purge(); SceneChangeNotify(); globalOutputStream() << MSG_PREFIX "Portals unloaded.\n"; } - else if ( !strcmp( p,Q3R_CMD_SHOW_2D ) ) { + else if ( !strcmp( p, Q3R_CMD_SHOW_2D ) ) { portals.show_2d = !portals.show_2d; SceneChangeNotify(); - SaveConfig(); if ( portals.show_2d ) { globalOutputStream() << MSG_PREFIX "Portals will be rendered in 2D view.\n"; @@ -225,9 +229,8 @@ void QERPlug_Dispatch( const char* p, float* vMin, float* vMax, bool bSingleBrus globalOutputStream() << MSG_PREFIX "Portals will NOT be rendered in 2D view.\n"; } } - else if ( !strcmp( p,Q3R_CMD_SHOW_3D ) ) { + else if ( !strcmp( p, Q3R_CMD_SHOW_3D ) ) { portals.show_3d = !portals.show_3d; - SaveConfig(); SceneChangeNotify(); @@ -238,9 +241,8 @@ void QERPlug_Dispatch( const char* p, float* vMin, float* vMax, bool bSingleBrus globalOutputStream() << MSG_PREFIX "Portals will NOT be rendered in 3D view.\n"; } } - else if ( !strcmp( p,Q3R_CMD_OPTIONS ) ) { + else if ( !strcmp( p, Q3R_CMD_OPTIONS ) ) { DoConfigDialog(); - SaveConfig(); SceneChangeNotify(); } diff --git a/contrib/prtview/prtview.h b/contrib/prtview/prtview.h index c7a55dd9..416bb018 100644 --- a/contrib/prtview/prtview.h +++ b/contrib/prtview/prtview.h @@ -21,10 +21,4 @@ #define MSG_PREFIX "Portal Viewer plugin: " -void InitInstance(); -void SaveConfig(); - -int INIGetInt( const char *key, int def ); -void INISetInt( const char *key, int val, const char *comment = 0 ); - extern class QWidget *g_pRadiantWnd; diff --git a/libs/profile/profile2.h b/libs/profile/profile2.h new file mode 100644 index 00000000..ebbb0914 --- /dev/null +++ b/libs/profile/profile2.h @@ -0,0 +1,117 @@ +/* + Copyright (c) 2001, Loki software, inc. + All rights reserved. + + Redistribution and use in source and binary forms, with or without modification, + are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this list + of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, this + list of conditions and the following disclaimer in the documentation and/or + other materials provided with the distribution. + + Neither the name of Loki software nor the names of its contributors may be used + to endorse or promote products derived from this software without specific prior + written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY + DIRECT,INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include "stream/textfilestream.h" +#include "stream/textstream.h" +#include "stream/stringstream.h" +#include +#include + +class IniFile +{ + // section key value + std::map> m_sections; +public: + bool read( const char *filename ){ + TextFileInputStream inputFile( filename ); + if( inputFile.failed() ){ + return false; + } + SingleCharacterInputStream bufferedInput( inputFile ); + StringBuffer line, section, key; + + const auto isSpace = []( char c ) -> bool { return c <= 32; }; + const auto trimTrailing = [isSpace]( StringBuffer& buf ){ while( !buf.empty() && isSpace( buf.back() ) ) buf.pop_back(); }; + /* filters comments and leading spaces */ + const auto getLine = [&bufferedInput, &line, isSpace]() -> bool { + line.clear(); + for ( char c; bufferedInput.readChar( c ); ){ + if( c == '\n' ){ // got line + return true; + } + else if( c == ';' && ( line.empty() || isSpace( line.back() ) ) ){ // entire or trailing comment + while( bufferedInput.readChar( c ) && c != '\n' ){} // skip it + return true; + } + else if( line.empty() && isSpace( c ) ){ // skip leading spaces + continue; + } + line.push_back( c ); + } + return !line.empty(); // last line w/o '\n' + }; + + while( getLine() ){ + trimTrailing( line ); + if( line.front() == '[' ){ // section + if( line.back() == ']' ){ + section.clear(); + section.push_range( line.c_str() + 1, &line.back() ); + } + } + else if( char *p = strchr( line.c_str(), '=' ) ){ // key + key.clear(); + key.push_range( line.c_str(), p ); + trimTrailing( key ); + while( isSpace( *++p ) && !string_empty( p ) ){} // skip leading value spaces + if( !key.empty() && !section.empty() ) + m_sections[ section.c_str() ][ key.c_str() ] = p; + } + } + + return true; + } + bool write( const char *filename ) const { + TextFileOutputStream outFile( filename ); + if( outFile.failed() ){ + return false; + } + + for( const auto& [ section, keyvalue ] : m_sections ){ + outFile << '[' << section << ']' << '\n'; + for( const auto& [ key, value ] : keyvalue ){ + outFile << key << '=' << value << '\n'; + } + } + + return true; + } + void setValue( const char *section, const char *key, const char *value ){ + m_sections[ section ][ key ] = value; + } + std::optional getValue( const char *section, const char *key ) const { + if( auto sec = m_sections.find( section ); sec != m_sections.cend() ) + if( auto k = sec->second.find( key ); k != sec->second.cend() ) + return k->second.c_str(); + return {}; + } +}; \ No newline at end of file diff --git a/libs/stream/stringstream.h b/libs/stream/stringstream.h index 3e6e91cb..2bd2e02f 100644 --- a/libs/stream/stringstream.h +++ b/libs/stream/stringstream.h @@ -78,6 +78,12 @@ public: return &( *m_string.begin() ); } + char& front(){ + return *begin(); + } + const char& front() const { + return *begin(); + } char& back(){ return *( end() - 1 ); } diff --git a/radiant/commands.cpp b/radiant/commands.cpp index f9cccc2e..431d7270 100644 --- a/radiant/commands.cpp +++ b/radiant/commands.cpp @@ -429,7 +429,7 @@ void DoCommandListDlg(){ -#include "profile/profile.h" +#include "profile/profile2.h" const char* const COMMANDS_VERSION = "1.0-gtk-accelnames"; @@ -454,25 +454,24 @@ void SaveCommandMap( const char* path ){ class ReadCommandMap { - const char* m_filename; + const IniFile& m_ini; std::size_t m_count; public: - ReadCommandMap( const char* filename ) : m_filename( filename ), m_count( 0 ){ + ReadCommandMap( const IniFile& ini ) : m_ini( ini ), m_count( 0 ){ } void operator()( const char* name, QKeySequence& accelerator ){ - char value[1024]; - if ( read_var( m_filename, "Commands", name, value ) ) { - if ( string_empty( value ) ) { + if ( auto value = m_ini.getValue( "Commands", name ) ) { + if ( string_empty( *value ) ) { accelerator = {}; } else{ - accelerator = QKeySequence( value ); + accelerator = QKeySequence( *value ); if ( QKeySequence_valid( accelerator ) ) { ++m_count; } else { - globalWarningStream() << "WARNING: failed to parse user command " << makeQuoted( name ) << ": unknown key " << makeQuoted( value ) << '\n'; + globalWarningStream() << "WARNING: failed to parse user command " << makeQuoted( name ) << ": unknown key " << makeQuoted( *value ) << '\n'; } } } @@ -485,24 +484,15 @@ public: void LoadCommandMap( const char* path ){ const auto strINI = StringStream( path, "shortcuts.ini" ); - FILE* f = fopen( strINI, "r" ); - if ( f != 0 ) { - fclose( f ); + if ( IniFile ini; ini.read( strINI ) ) { globalOutputStream() << "loading custom shortcuts list from " << makeQuoted( strINI ) << '\n'; - Version version = version_parse( COMMANDS_VERSION ); - Version dataVersion = { 0, 0 }; - - { - char value[1024]; - if ( read_var( strINI, "Version", "number", value ) ) { - dataVersion = version_parse( value ); - } - } + const Version version = version_parse( COMMANDS_VERSION ); + const Version dataVersion = version_parse( ini.getValue( "Version", "number" ).value_or( "" ) ); if ( version_compatible( version, dataVersion ) ) { globalOutputStream() << "commands import: data version " << dataVersion << " is compatible with code version " << version << '\n'; - ReadCommandMap visitor( strINI ); + ReadCommandMap visitor( ini ); GlobalShortcuts_foreach( visitor ); globalOutputStream() << "parsed " << visitor.count() << " custom shortcuts\n"; }