diff --git a/libs/os/path.h b/libs/os/path.h index 827cb1c2..b20e0336 100644 --- a/libs/os/path.h +++ b/libs/os/path.h @@ -207,34 +207,36 @@ inline MatchFileExtension matchFileExtension( const char* extension, co return MatchFileExtension( extension, functor ); } -class PathExtensionless -{ -public: -const char* m_path; -PathExtensionless( const char* path ) : m_path( path ){ +/// \brief Returns portion of \p path without .ext part. +inline StringRange PathExtensionless( const char *path ){ + return StringRange( path, path_get_filename_base_end( path ) ); } -}; -/// \brief Writes \p path to \p ostream without .ext part. -template -TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, const PathExtensionless& path ){ - ostream << StringRange( path.m_path, path_get_filename_base_end( path.m_path ) ); - return ostream; +/// \brief Returns portion of \p path without directory and .ext parts. +inline StringRange PathFilename( const char *path ){ + return StringRange( path_get_filename_start( path ), path_get_filename_base_end( path ) ); +} + +/// \brief Returns portion of \p path without filename part. +inline StringRange PathFilenameless( const char *path ){ + return StringRange( path, path_get_filename_start( path ) ); } class PathCleaned { public: const char* m_path; -PathCleaned( const char* path ) : m_path( path ){ +const char* m_end; +PathCleaned( const char* path ) : m_path( path ), m_end( path + std::strlen( path ) ){ +} +PathCleaned( const StringRange& range ) : m_path( range.first ), m_end( range.last ){ } }; /// \brief Writes \p path to \p ostream with dos-style separators replaced by unix-style separators. template TextOutputStreamType& ostream_write( TextOutputStreamType& ostream, const PathCleaned& path ){ - const char* i = path.m_path; - for (; *i != '\0'; ++i ) + for ( const char* i = path.m_path; i != path.m_end; ++i ) { if ( *i == '\\' ) { ostream << '/'; diff --git a/plugins/entity/miscmodel.cpp b/plugins/entity/miscmodel.cpp index 0f82583f..91848ab7 100644 --- a/plugins/entity/miscmodel.cpp +++ b/plugins/entity/miscmodel.cpp @@ -67,9 +67,7 @@ class RemapKeysObserver : public Entity::Observer, public ModelSkin const char* split = strchr( value, ';' ); if( split != nullptr ){ m_from = { value, split }; - StringOutputStream stream( 64 ); - stream << PathCleaned( split + 1 ); - m_to = stream.c_str(); + m_to = StringOutputStream( 64 )( PathCleaned( split + 1 ) ).c_str(); } else{ m_from = ""; diff --git a/plugins/entity/modelskinkey.h b/plugins/entity/modelskinkey.h index 34d91112..e03402a1 100644 --- a/plugins/entity/modelskinkey.h +++ b/plugins/entity/modelskinkey.h @@ -31,9 +31,7 @@ #include "traverselib.h" inline void parseTextureName( CopiedString& name, const char* token ){ - StringOutputStream cleaned( 256 ); - cleaned << PathCleaned( token ); - name = StringRange( cleaned.c_str(), path_get_filename_base_end( cleaned.c_str() ) ); // remove extension + name = StringOutputStream( 256 )( PathCleaned( PathExtensionless( token ) ) ).c_str(); // remove extension } class ModelSkinKey : public ModuleObserver diff --git a/plugins/entity/skincache.cpp b/plugins/entity/skincache.cpp index 4517f48c..a608d1fa 100644 --- a/plugins/entity/skincache.cpp +++ b/plugins/entity/skincache.cpp @@ -38,9 +38,7 @@ #include "stringio.h" void parseShaderName( CopiedString& name, const char* token ){ - StringOutputStream cleaned( 256 ); - cleaned << PathCleaned( token ); - name = cleaned.c_str(); + name = StringOutputStream( 256 )( PathCleaned( token ) ).c_str(); } class Doom3ModelSkin diff --git a/plugins/md3model/model.h b/plugins/md3model/model.h index a00e894e..b9a0cad4 100644 --- a/plugins/md3model/model.h +++ b/plugins/md3model/model.h @@ -66,9 +66,7 @@ inline VertexPointer vertexpointer_arbitrarymeshvertex( const ArbitraryMeshVerte } inline void parseTextureName( CopiedString& name, const char* token ){ - StringOutputStream cleaned( 256 ); - cleaned << PathCleaned( token ); - name = StringRange( cleaned.c_str(), path_get_filename_base_end( cleaned.c_str() ) ); // remove extension + name = StringOutputStream( 256 )( PathCleaned( PathExtensionless( token ) ) ).c_str(); // remove extension } // generic renderable triangle surface diff --git a/plugins/shaders/shaders.cpp b/plugins/shaders/shaders.cpp index ce1b803a..04835d8b 100644 --- a/plugins/shaders/shaders.cpp +++ b/plugins/shaders/shaders.cpp @@ -232,9 +232,7 @@ typedef CopiedString TextureExpression; //++timo FIXME: we need to put code somewhere to detect when two shaders that are case insensitive equal are present template void parseTextureName( StringType& name, const char* token ){ - StringOutputStream cleaned( 256 ); - cleaned << PathCleaned( token ); - name = CopiedString( StringRange( cleaned.c_str(), path_get_filename_base_end( cleaned.c_str() ) ) ).c_str(); // remove extension + name = StringOutputStream( 256 )( PathCleaned( PathExtensionless( token ) ) ).c_str(); // remove extension } bool Tokeniser_parseTextureName( Tokeniser& tokeniser, TextureExpression& name ){ @@ -1610,12 +1608,9 @@ void ShaderList_addFromArchive( const char *archivename ){ return; } - StringOutputStream shaderlist( 256 ); - shaderlist << DirectoryCleaned( shaderpath ) << "shaderlist.txt"; - Archive *archive = GlobalFileSystem().getArchive( archivename, false ); if ( archive ) { - ArchiveTextFile *file = archive->openTextFile( shaderlist.c_str() ); + ArchiveTextFile *file = archive->openTextFile( StringOutputStream( 64 )( DirectoryCleaned( shaderpath ), "shaderlist.txt" ).c_str() ); if ( file ) { globalOutputStream() << "Found shaderlist.txt in " << archivename << "\n"; BuildShaderList( file->getInputStream() ); @@ -1658,8 +1653,7 @@ void Shaders_Load(){ const char* shaderPath = GlobalRadiant().getGameDescriptionKeyValue( "shaderpath" ); if ( !string_empty( shaderPath ) ) { - StringOutputStream path( 256 ); - path << DirectoryCleaned( shaderPath ); + const auto path = StringOutputStream( 64 )( DirectoryCleaned( shaderPath ) ); if ( g_useShaderList ) { // preload shader files that have been listed in shaderlist.txt diff --git a/radiant/autosave.cpp b/radiant/autosave.cpp index cb66cf49..fb9c9775 100644 --- a/radiant/autosave.cpp +++ b/radiant/autosave.cpp @@ -53,31 +53,24 @@ void Map_Snapshot(){ // 1. make sure the snapshot directory exists (create it if it doesn't) // 2. find out what the lastest save is based on number // 3. inc that and save the map - const char* path = Map_Name( g_map ); - const char* name = path_get_filename_start( path ); - - StringOutputStream snapshotsDir( 256 ); - snapshotsDir << StringRange( path, name ) << "snapshots"; + const char* mapname = Map_Name( g_map ); + const auto snapshotsDir = StringOutputStream( 256 )( PathFilenameless( mapname ), "snapshots" ); if ( file_exists( snapshotsDir.c_str() ) || Q_mkdir( snapshotsDir.c_str() ) ) { std::size_t lSize = 0; - StringOutputStream strNewPath( 256 ); - strNewPath << snapshotsDir.c_str() << '/' << name; + const auto strNewPath = StringOutputStream( 256 )( snapshotsDir.c_str(), '/', mapname ); + const char* ext = path_get_filename_base_end( strNewPath.c_str() ); StringOutputStream snapshotFilename( 256 ); - for ( int nCount = 0; ; ++nCount ) { // The original map's filename is "/." // The snapshot's filename will be "/snapshots/.." - const char* end = path_get_filename_base_end( strNewPath.c_str() ); - snapshotFilename << StringRange( strNewPath.c_str(), end ) << '.' << nCount << end; + snapshotFilename( StringRange( strNewPath.c_str(), ext ), '.', nCount, ext ); if ( !DoesFileExist( snapshotFilename.c_str(), lSize ) ) { break; } - - snapshotFilename.clear(); } // save in the next available slot @@ -159,8 +152,7 @@ void QE_CheckAutoSave( void ){ { const char* name = Map_Name( g_map ); const char* extension = path_get_filename_base_end( name ); - StringOutputStream autosave( 256 ); - autosave << StringRange( name, extension ) << ".autosave" << extension; + const auto autosave = StringOutputStream( 256 )( StringRange( name, extension ), ".autosave", extension ); Map_SaveFile( autosave.c_str() ); } } diff --git a/radiant/eclass_def.cpp b/radiant/eclass_def.cpp index 7a7baf29..4ae3cd05 100644 --- a/radiant/eclass_def.cpp +++ b/radiant/eclass_def.cpp @@ -275,9 +275,7 @@ EntityClass *Eclass_InitFromText( const char *text ){ e->m_comments = text; setSpecialLoad( e, "model=", e->m_modelpath ); - StringOutputStream buffer( string_length( e->m_modelpath.c_str() ) ); - buffer << PathCleaned( e->m_modelpath.c_str() ); - e->m_modelpath = buffer.c_str(); + e->m_modelpath = StringOutputStream( 256 )( PathCleaned( e->m_modelpath.c_str() ) ).c_str(); if ( !e->fixedsize ) { EntityClass_insertAttribute( *e, "angle", EntityClassAttribute( "direction", "Direction" ) ); diff --git a/radiant/eclass_doom3.cpp b/radiant/eclass_doom3.cpp index 91215d8f..7cc25fb7 100644 --- a/radiant/eclass_doom3.cpp +++ b/radiant/eclass_doom3.cpp @@ -359,9 +359,7 @@ static bool EntityClass_parse( EntityClass& entityClass, Tokeniser& tokeniser ){ const char* token; PARSE_RETURN_FALSE_IF_FAIL( EntityClassDoom3_parseString( tokeniser, token ) ); entityClass.fixedsize = true; - StringOutputStream buffer( 256 ); - buffer << PathCleaned( token ); - entityClass.m_modelpath = buffer.c_str(); + entityClass.m_modelpath = StringOutputStream( 256 )( PathCleaned( token ) ).c_str(); } else if ( string_equal( key, "editor_color" ) ) { const char* value; diff --git a/radiant/eclass_fgd.cpp b/radiant/eclass_fgd.cpp index 330ee5a9..1018af34 100644 --- a/radiant/eclass_fgd.cpp +++ b/radiant/eclass_fgd.cpp @@ -166,9 +166,7 @@ void EntityClassFGD_parseClass( Tokeniser& tokeniser, bool fixedsize, bool isBas } else if ( string_equal( property, "iconsprite" ) ) { ASSERT_MESSAGE( EntityClassFGD_parseToken( tokeniser, "(" ), PARSE_ERROR ); - StringOutputStream buffer( 256 ); - buffer << PathCleaned( tokeniser.getToken() ); - entityClass->m_modelpath = buffer.c_str(); + entityClass->m_modelpath = StringOutputStream( 256 )( PathCleaned( tokeniser.getToken() ) ).c_str(); ASSERT_MESSAGE( EntityClassFGD_parseToken( tokeniser, ")" ), PARSE_ERROR ); } else if ( string_equal( property, "sprite" ) @@ -504,10 +502,7 @@ void EntityClassFGD_parse( TextInputStream& inputStream, const char* path ){ } // hl2 below else if ( string_equal( blockType, "@include" ) ) { - StringOutputStream includePath( 256 ); - includePath << StringRange( path, path_get_filename_start( path ) ); - includePath << tokeniser.getToken(); - EntityClassFGD_loadFile( includePath.c_str() ); + EntityClassFGD_loadFile( StringOutputStream( 256 )( PathFilenameless( path ), tokeniser.getToken() ).c_str() ); } else if ( string_equal( blockType, "@mapsize" ) ) { ASSERT_MESSAGE( EntityClassFGD_parseToken( tokeniser, "(" ), PARSE_ERROR ); diff --git a/radiant/eclass_xml.cpp b/radiant/eclass_xml.cpp index 94df80af..4f281012 100644 --- a/radiant/eclass_xml.cpp +++ b/radiant/eclass_xml.cpp @@ -293,9 +293,7 @@ ClassImporter( EntityClassCollector& collector, ListAttributeTypes& listTypes, c const char* model = element.attribute( "model" ); if ( !string_empty( model ) ) { - StringOutputStream buffer( 256 ); - buffer << PathCleaned( model ); - m_eclass->m_modelpath = buffer.c_str(); + m_eclass->m_modelpath = StringOutputStream( 256 )( PathCleaned( model ) ).c_str(); } const char* type = element.name(); diff --git a/radiant/environment.cpp b/radiant/environment.cpp index 6fbd9018..3a780bc9 100644 --- a/radiant/environment.cpp +++ b/radiant/environment.cpp @@ -198,9 +198,7 @@ CopiedString g_openMapByCmd; void cmdMap(){ for ( int i = 1; i < g_argc; ++i ) if( extension_equal( path_get_extension( g_argv[i] ), "map" ) ){ - StringOutputStream stream( 256 ); - stream << PathCleaned( g_argv[i] ); - g_openMapByCmd = stream.c_str(); + g_openMapByCmd = StringOutputStream( 256 )( PathCleaned( g_argv[i] ) ).c_str(); return; } } @@ -257,14 +255,12 @@ void environment_init( int argc, char* argv[] ){ ASSERT_MESSAGE( !string_empty( app_filepath.c_str() ), "failed to deduce app path" ); // NOTE: we build app path with a trailing '/' // it's a general convention in Radiant to have the slash at the end of directories - app_path = StringRange( real, path_get_filename_start( real ) ); + app_path = PathFilenameless( real ); } if ( !portable_app_setup() ) { - StringOutputStream home( 256 ); - home << DirectoryCleaned( g_get_home_dir() ) << ".netradiant/"; - Q_mkdir( home.c_str() ); - home_path = home.c_str(); + home_path = StringOutputStream( 256 )( DirectoryCleaned( g_get_home_dir() ), ".netradiant/" ).c_str(); + Q_mkdir( home_path.c_str() ); } gamedetect(); cmdMap(); @@ -282,10 +278,8 @@ void environment_init( int argc, char* argv[] ){ char filename[MAX_PATH + 1]; GetModuleFileName( 0, filename, MAX_PATH ); - StringOutputStream stream( 256 ); - stream << PathCleaned( filename ); - app_filepath = stream.c_str(); - app_path = StringRange( stream.c_str(), path_get_filename_start( stream.c_str() ) ); + app_filepath = StringOutputStream( 256 )( PathCleaned( filename ) ).c_str(); + app_path = PathFilenameless( app_filepath.c_str() ); } if ( !portable_app_setup() ) { diff --git a/radiant/findtexturedialog.cpp b/radiant/findtexturedialog.cpp index 615b2940..206c5177 100644 --- a/radiant/findtexturedialog.cpp +++ b/radiant/findtexturedialog.cpp @@ -79,11 +79,8 @@ static bool g_bFindActive = true; namespace { void FindTextureDialog_apply(){ - StringOutputStream find( 256 ); - StringOutputStream replace( 256 ); - - find << "textures/" << g_FindTextureDialog.m_strFind.c_str(); - replace << "textures/" << PathCleaned( g_FindTextureDialog.m_strReplace.c_str() ); + const auto find = StringOutputStream( 256 )( "textures/", g_FindTextureDialog.m_strFind.c_str() ); + const auto replace = StringOutputStream( 256 )( "textures/", PathCleaned( g_FindTextureDialog.m_strReplace.c_str() ) ); FindReplaceTextures( find.c_str(), replace.c_str(), g_FindTextureDialog.m_bSelectedOnly ); } diff --git a/radiant/mainframe.cpp b/radiant/mainframe.cpp index 1a81e68d..4941e96c 100644 --- a/radiant/mainframe.cpp +++ b/radiant/mainframe.cpp @@ -332,8 +332,7 @@ void EnginePath_Unrealise(){ } void setEnginePath( CopiedString& self, const char* value ){ - StringOutputStream buffer( 256 ); - buffer << DirectoryCleaned( value ); + const auto buffer = StringOutputStream( 256 )( DirectoryCleaned( value ) ); if ( !path_equal( buffer.c_str(), self.c_str() ) ) { #if 0 while ( !ConfirmModified( "Paths Changed" ) ) @@ -3736,9 +3735,7 @@ void MainFrame_Construct(){ #error "unknown platform" #endif ; - StringOutputStream path( 256 ); - path << DirectoryCleaned( g_pGameDescription->getRequiredKeyValue( ENGINEPATH_ATTRIBUTE ) ); - g_strEnginePath = path.c_str(); + g_strEnginePath = StringOutputStream( 256 )( DirectoryCleaned( g_pGameDescription->getRequiredKeyValue( ENGINEPATH_ATTRIBUTE ) ) ).c_str(); } diff --git a/radiant/modelwindow.cpp b/radiant/modelwindow.cpp index 2f3001ea..0ea0d258 100644 --- a/radiant/modelwindow.cpp +++ b/radiant/modelwindow.cpp @@ -1156,8 +1156,7 @@ public: // parse string of format *pathToLoad/depth*path2ToLoad/depth* // */depth* for root path ModelFolders( const char* pathsString ){ - StringOutputStream str( 128 ); - str << PathCleaned( pathsString ); + const auto str = StringOutputStream( 128 )( PathCleaned( pathsString ) ); const char* start = str.c_str(); while( 1 ){ diff --git a/radiant/qe3.cpp b/radiant/qe3.cpp index be1c82e2..98c3022c 100644 --- a/radiant/qe3.cpp +++ b/radiant/qe3.cpp @@ -184,9 +184,7 @@ void bsp_init(){ } { - StringOutputStream name( 256 ); - name << StringRange( path_get_filename_start( mapname ), path_get_filename_base_end( mapname ) ); - build_set_variable( "MapName", name.c_str() ); + build_set_variable( "MapName", StringOutputStream( 64 )( PathFilename( mapname ) ).c_str() ); } } @@ -285,8 +283,7 @@ void RunBSP( const char* name ){ if ( g_WatchBSP_Enabled && monitor ) { // grab the file name for engine running const char* fullname = Map_Name( g_map ); - StringOutputStream bspname( 64 ); - bspname << StringRange( path_get_filename_start( fullname ), path_get_filename_base_end( fullname ) ); + const auto bspname = StringOutputStream( 64 )( PathFilename( fullname ) ); BuildMonitor_Run( listener.array(), bspname.c_str() ); } else diff --git a/radiant/surfacedialog.cpp b/radiant/surfacedialog.cpp index 91f6d08e..48b95874 100644 --- a/radiant/surfacedialog.cpp +++ b/radiant/surfacedialog.cpp @@ -1373,8 +1373,7 @@ void SurfaceInspector::Update(){ =============== */ void SurfaceInspector::ApplyShader(){ - StringOutputStream name( 256 ); - name << GlobalTexturePrefix_get() << PathCleaned( gtk_entry_get_text( m_texture ) ); + const auto name = StringOutputStream( 256 )( GlobalTexturePrefix_get(), PathCleaned( gtk_entry_get_text( m_texture ) ) ); // TTimo: detect and refuse invalid texture names (at least the ones with spaces) if ( !texdef_name_valid( name.c_str() ) ) { diff --git a/radiant/texwindow.cpp b/radiant/texwindow.cpp index cc6e0cc6..1baa427f 100644 --- a/radiant/texwindow.cpp +++ b/radiant/texwindow.cpp @@ -95,7 +95,7 @@ void TextureGroups_addWad( TextureGroups& groups, const char* archive ){ #if 1 groups.insert( archive ); #else - CopiedString archiveBaseName( path_get_filename_start( archive ), path_get_filename_base_end( archive ) ); + CopiedString archiveBaseName( PathFilename( archive ) ); groups.insert( archiveBaseName ); #endif } @@ -696,7 +696,7 @@ class LoadShaderVisitor : public Archive::Visitor { public: void visit( const char* name ){ - IShader* shader = QERApp_Shader_ForName( CopiedString( StringRange( name, path_get_filename_base_end( name ) ) ).c_str() ); + IShader* shader = QERApp_Shader_ForName( CopiedString( PathExtensionless( name ) ).c_str() ); shader->DecRef(); } };