rewrite ini reader/writer

This commit is contained in:
Garux
2024-12-04 06:20:37 +05:00
parent 54dfa0df74
commit 7357b6ed57
6 changed files with 235 additions and 134 deletions
-8
View File
@@ -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
+101 -99
View File
@@ -22,7 +22,7 @@
#include <cstdio>
#include <cstdlib>
#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();
}
-6
View File
@@ -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;
+117
View File
@@ -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 <optional>
#include <map>
class IniFile
{
// section key value
std::map<CopiedString, std::map<CopiedString, CopiedString>> m_sections;
public:
bool read( const char *filename ){
TextFileInputStream inputFile( filename );
if( inputFile.failed() ){
return false;
}
SingleCharacterInputStream<TextFileInputStream> 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<const char*> 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 {};
}
};
+6
View File
@@ -78,6 +78,12 @@ public:
return &( *m_string.begin() );
}
char& front(){
return *begin();
}
const char& front() const {
return *begin();
}
char& back(){
return *( end() - 1 );
}
+11 -21
View File
@@ -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";
}