From: TimePath <andrew.hardaker1995@gmail.com>
Date: Tue, 8 Aug 2017 12:19:10 +0000 (+1000)
Subject: Implement buffer operations
X-Git-Url: https://git.rm.cloudns.org/?a=commitdiff_plain;h=550b552a0b1912ac0ef62ffc611e23860749df50;p=xonotic%2Fnetradiant.git

Implement buffer operations
---

diff --git a/libs/util/buffer.h b/libs/util/buffer.h
index 9ce31d62..a621f492 100644
--- a/libs/util/buffer.h
+++ b/libs/util/buffer.h
@@ -1,6 +1,10 @@
 #ifndef INCLUDED_BUFFER_H
 #define INCLUDED_BUFFER_H
 
+#include <cstdarg>
+#include <cstdio>
+#include <cstring>
+
 namespace u {
 
     using byte = char;
@@ -59,9 +63,44 @@ namespace u {
             return this->data();
         }
 
-        operator byte *() {
+        operator cstring() const {
+            return c_str();
+        }
+
+        std::size_t strlen() const {
+            return ::strlen(c_str());
+        }
+
+        byte *mut() {
             return this->data();
         }
+
+//        operator byte *() {
+//            return mut();
+//        }
+
+        void terminate(long offset = -1) {
+            if (offset < 0) {
+                offset += this->size();
+            }
+            mut()[offset] = '\0';
+        }
+
+        void copy(cstring str, unsigned int offset = 0, unsigned int limit = 0) {
+            if (!limit) {
+                limit = this->size() - offset;
+            }
+            strncpy(mut() + offset, str, limit);
+        }
+
+        __attribute__((format(printf, 2, 3)))
+        void sprintf(const char *format, ...) {
+            // todo: check for overflow
+            va_list argptr;
+            va_start(argptr, format);
+            vsprintf(this->data(), format, argptr);
+            va_end(argptr);
+        }
     };
 
     template<int sz>
diff --git a/radiant/brushxml.h b/radiant/brushxml.h
index d312591c..3059f072 100644
--- a/radiant/brushxml.h
+++ b/radiant/brushxml.h
@@ -236,13 +236,13 @@ inline void FacePolygon_exportXML( const Winding& w, const BasicVector3<double>&
 
 	auto tmp = u::buffer<32>();
 
-	sprintf( tmp, "%f", normal.x() );
+    tmp.sprintf( "%f", normal.x() );
 	element.insertAttribute( "nx", tmp );
 
-	sprintf( tmp, "%f", normal.y() );
+    tmp.sprintf( "%f", normal.y() );
 	element.insertAttribute( "ny", tmp );
 
-	sprintf( tmp, "%f", normal.z() );
+    tmp.sprintf( "%f", normal.z() );
 	element.insertAttribute( "nz", tmp );
 
 	importer.pushElement( element );
@@ -251,19 +251,19 @@ inline void FacePolygon_exportXML( const Winding& w, const BasicVector3<double>&
 	{
 		DynamicElement c( "vertex" );
 
-		sprintf( tmp, "%f", w.points[i].vertex.x() );
+		tmp.sprintf( "%f", w.points[i].vertex.x() );
 		c.insertAttribute( "x", tmp );
 
-		sprintf( tmp, "%f", w.points[i].vertex.y() );
+		tmp.sprintf( "%f", w.points[i].vertex.y() );
 		c.insertAttribute( "y", tmp );
 
-		sprintf( tmp, "%f", w.points[i].vertex.z() );
+		tmp.sprintf( "%f", w.points[i].vertex.z() );
 		c.insertAttribute( "z", tmp );
 
-		sprintf( tmp, "%f", w.points[i].texcoord.x() );
+		tmp.sprintf( "%f", w.points[i].texcoord.x() );
 		c.insertAttribute( "s", tmp );
 
-		sprintf( tmp, "%f", w.points[i].texcoord.y() );
+		tmp.sprintf( "%f", w.points[i].texcoord.y() );
 		c.insertAttribute( "t", tmp );
 
 		importer.pushElement( c );
diff --git a/radiant/commands.cpp b/radiant/commands.cpp
index 06dc7575..1077b3a3 100644
--- a/radiant/commands.cpp
+++ b/radiant/commands.cpp
@@ -539,7 +539,7 @@ ReadCommandMap( const char* filename ) : m_filename( filename ), m_count( 0 ){
 }
 void visit( const char* name, Accelerator& accelerator ){
 	auto value = u::buffer<1024>();
-	if ( read_var( m_filename, "Commands", name, value ) ) {
+	if ( read_var( m_filename, "Commands", name, value.mut() ) ) {
 		if ( string_empty( value ) ) {
 			accelerator.key = 0;
 			accelerator.modifiers = (GdkModifierType)0;
@@ -577,7 +577,7 @@ void LoadCommandMap( const char* path ){
 
 		{
 			auto value = u::buffer<1024>();
-			if ( read_var( strINI.c_str(), "Version", "number", value ) ) {
+			if ( read_var( strINI.c_str(), "Version", "number", value.mut() ) ) {
 				dataVersion = version_parse( value );
 			}
 		}
diff --git a/radiant/eclass_def.cpp b/radiant/eclass_def.cpp
index a619ed74..09192616 100644
--- a/radiant/eclass_def.cpp
+++ b/radiant/eclass_def.cpp
@@ -82,10 +82,10 @@ bool com_eof;
  */
 const char *COM_Parse( const char *data ){
 	int c;
-	int len;
 
-	len = 0;
-	com_token[0] = 0;
+	int len = 0;
+	auto buf = com_token.mut();
+	buf[0] = 0;
 
 	if ( !data ) {
 		return 0;
@@ -117,26 +117,26 @@ skipwhite:
 		{
 			c = *data++;
 			if ( c == '\"' ) {
-				com_token[len] = 0;
+				buf[len] = 0;
 				return data;
 			}
-			com_token[len] = c;
+			buf[len] = c;
 			len++;
 		} while ( 1 );
 	}
 
 // parse single characters
 	if ( c == '{' || c == '}' || c == ')' || c == '(' || c == '\'' || c == ':' ) {
-		com_token[len] = c;
+		buf[len] = c;
 		len++;
-		com_token[len] = 0;
+		buf[len] = 0;
 		return data + 1;
 	}
 
 // parse a regular word
 	do
 	{
-		com_token[len] = c;
+		buf[len] = c;
 		data++;
 		len++;
 		c = *data;
@@ -145,7 +145,7 @@ skipwhite:
 		}
 	} while ( c > 32 );
 
-	com_token[len] = 0;
+	buf[len] = 0;
 	return data;
 }
 
@@ -253,7 +253,7 @@ EntityClass *Eclass_InitFromText( const char *text ){
 	// get the flags
 	{
 		// copy to the first /n
-		char* p = parms;
+		char* p = parms.mut();
 		while ( *text && *text != '\n' )
 			*p++ = *text++;
 		*p = 0;
diff --git a/radiant/entity.cpp b/radiant/entity.cpp
index 87cf9cd0..b48655c5 100644
--- a/radiant/entity.cpp
+++ b/radiant/entity.cpp
@@ -356,7 +356,7 @@ void Entity_createFromSelection( const char* name, const Vector3& origin ){
 			if ( DoLightIntensityDlg( &intensity ) == eIDOK ) {
 				g_iLastLightIntensity = intensity;
 				auto buf = u::buffer<30>();
-				sprintf( buf, "255 255 255 %d", intensity );
+				buf.sprintf( "255 255 255 %d", intensity );
 				Node_getEntity( node )->setKeyValue( "_light", buf );
 			}
 		}
@@ -368,7 +368,7 @@ void Entity_createFromSelection( const char* name, const Vector3& origin ){
 			if ( DoLightIntensityDlg( &intensity ) == eIDOK ) {
 				g_iLastLightIntensity = intensity;
 				auto buf = u::buffer<10>();
-				sprintf( buf, "%d", intensity );
+				buf.sprintf( "%d", intensity );
 				Node_getEntity( node )->setKeyValue( "light", buf );
 			}
 		}
@@ -474,7 +474,7 @@ void Entity_normalizeColor(){
 					NormalizeColor( g_entity_globals.color_entity );
 
 					auto buffer = u::buffer<128>();
-					sprintf( buffer, "%g %g %g", g_entity_globals.color_entity[0],
+					buffer.sprintf( "%g %g %g", g_entity_globals.color_entity[0],
 							 g_entity_globals.color_entity[1],
 							 g_entity_globals.color_entity[2] );
 
@@ -510,7 +510,7 @@ void Entity_setColour(){
 				}
 
 				auto buffer = u::buffer<128>();
-				sprintf( buffer, "%g %g %g", g_entity_globals.color_entity[0],
+                buffer.sprintf( "%g %g %g", g_entity_globals.color_entity[0],
 						 g_entity_globals.color_entity[1],
 						 g_entity_globals.color_entity[2] );
 
diff --git a/radiant/entityinspector.cpp b/radiant/entityinspector.cpp
index 1e6b5d06..4488334d 100644
--- a/radiant/entityinspector.cpp
+++ b/radiant/entityinspector.cpp
@@ -1015,7 +1015,7 @@ void EntityInspector_applySpawnflags(){
 		f |= v << spawn_table[i];
 	}
 
-	sprintf( sz, "%i", f );
+	sz.sprintf( "%i", f );
 	const char* value = ( f == 0 ) ? "" : sz;
 
 	{
diff --git a/radiant/environment.cpp b/radiant/environment.cpp
index 0d5c243a..ca294b4e 100644
--- a/radiant/environment.cpp
+++ b/radiant/environment.cpp
@@ -66,7 +66,7 @@ void gamedetect_found_game( const char *game, char *path ){
 
 	globalOutputStream() << "Detected game " << game << " in " << path << "\n";
 
-	sprintf( buf, "-%s-EnginePath", game );
+	buf.sprintf( "-%s-EnginePath", game );
 	argc = 0;
 	gamedetect_argv_buffer[argc++] = "-global-gamefile";
 	gamedetect_argv_buffer[argc++] = game;
@@ -116,13 +116,13 @@ void gamedetect(){
 		}
 	if ( !nogamedetect ) {
 		static auto buf = u::buffer<1024 + 64>();
-		strncpy( buf, environment_get_app_path(), sizeof( buf ) );
-		buf[sizeof( buf ) - 1 - 64] = 0;
-		if ( !strlen( buf ) ) {
+		buf.copy(environment_get_app_path());
+		buf.terminate(-64);
+		if ( !buf.strlen() ) {
 			return;
 		}
 
-		char *p = buf + strlen( buf ) - 1; // point directly on the slash of get_app_path
+		char *p = buf.mut() + buf.strlen() - 1; // point directly on the slash of get_app_path
 		while ( p != buf )
 		{
 			// TODO add more games to this
@@ -133,17 +133,17 @@ void gamedetect(){
 #elif defined( __APPLE__ )
 			if ( gamedetect_check_game( "nexuiz.game", "data/common-spog.pk3", "Nexuiz.app/Contents/Info.plist", buf, p - buf ) )
 #else
-			if ( gamedetect_check_game( "nexuiz.game", "data/common-spog.pk3", "nexuiz-linux-glx.sh", buf, p - buf ) )
+			if ( gamedetect_check_game( "nexuiz.game", "data/common-spog.pk3", "nexuiz-linux-glx.sh", buf.mut(), p - buf.c_str() ) )
 #endif
 			{ return; }
 
 			// try to detect Quetoo installs
-			if ( gamedetect_check_game( "quetoo.game", "default/icons/quetoo.png", NULL, buf, p - buf ) ) {
+			if ( gamedetect_check_game( "quetoo.game", "default/icons/quetoo.png", NULL, buf.mut(), p - buf.c_str() ) ) {
 				return;
 			}
 
 			// try to detect Warsow installs
-			if ( gamedetect_check_game( "warsow.game", "basewsw/dedicated_autoexec.cfg", NULL, buf, p - buf ) ) {
+			if ( gamedetect_check_game( "warsow.game", "basewsw/dedicated_autoexec.cfg", NULL, buf.mut(), p - buf.c_str() ) ) {
 				return;
 			}
 
diff --git a/radiant/error.cpp b/radiant/error.cpp
index 56a8a056..b1417000 100644
--- a/radiant/error.cpp
+++ b/radiant/error.cpp
@@ -60,10 +60,10 @@ void Error( const char *error, ... ){
 	auto text = u::buffer<4096>();
 
 	va_start( argptr,error );
-	vsprintf( text, error,argptr );
+	vsprintf( text.mut(), error,argptr );
 	va_end( argptr );
 
-	strcat( text, "\n" );
+	strcat( text.mut(), "\n" );
 
 #ifdef WIN32
 	if ( GetLastError() != 0 ) {
@@ -103,9 +103,9 @@ void Error( const char *error, ... ){
 	}
 #else
 	if ( errno != 0 ) {
-		strcat( text, "errno: " );
-		strcat( text, strerror( errno ) );
-		strcat( text, "\n" );
+		strcat( text.mut(), "errno: " );
+		strcat( text.mut(), strerror( errno ) );
+		strcat( text.mut(), "\n" );
 	}
 #endif
 
@@ -126,7 +126,7 @@ void Error( const char *error, ... ){
 	}
 #endif
 
-	strcat( text, "An unrecoverable error has occured.\n" );
+	strcat( text.mut(), "An unrecoverable error has occured.\n" );
 
 	ERROR_MESSAGE( text );
 
diff --git a/radiant/filetypes.cpp b/radiant/filetypes.cpp
index 115b1e26..9da5537f 100644
--- a/radiant/filetypes.cpp
+++ b/radiant/filetypes.cpp
@@ -93,10 +93,10 @@ const char* findModuleName( IFileTypeRegistry* registry, const char* moduleType,
 public:
 	SearchFileTypeList( const char* ext )
 		: m_moduleName( "" ){
-		m_pattern[0] = '*';
-		m_pattern[1] = '.';
-		strncpy( m_pattern + 2, ext, 125 );
-		m_pattern[127] = '\0';
+		m_pattern.mut()[0] = '*';
+		m_pattern.mut()[1] = '.';
+		m_pattern.copy(ext, 2);
+		m_pattern.terminate();
 	}
 	void addType( const char* moduleName, filetype_t type ){
 		if ( extension_equal( m_pattern, type.pattern ) ) {
diff --git a/radiant/gtkdlgs.cpp b/radiant/gtkdlgs.cpp
index 3486c1ba..0947e6ab 100644
--- a/radiant/gtkdlgs.cpp
+++ b/radiant/gtkdlgs.cpp
@@ -678,10 +678,10 @@ EMessageBoxReturn DoTextureLayout( float *fx, float *fy ){
 	// Initialize with last used values
 	auto buf = u::buffer<16>();
 
-	sprintf( buf, "%f", last_used_texture_layout_scale_x );
+	buf.sprintf( "%f", last_used_texture_layout_scale_x );
 	x.text( buf );
-	
-	sprintf( buf, "%f", last_used_texture_layout_scale_y );
+
+	buf.sprintf( "%f", last_used_texture_layout_scale_y );
 	y.text( buf );
 
 	// Set focus after intializing the values
@@ -901,7 +901,7 @@ EMessageBoxReturn DoLightIntensityDlg( int *intensity ){
 	}
 
 	auto buf = u::buffer<16>();
-	sprintf( buf, "%d", *intensity );
+	buf.sprintf( "%d", *intensity );
 	intensity_entry.text(buf);
 
 	EMessageBoxReturn ret = modal_dialog_show( window, dialog );
diff --git a/radiant/main.cpp b/radiant/main.cpp
index 270e8a5a..966bf7cd 100644
--- a/radiant/main.cpp
+++ b/radiant/main.cpp
@@ -112,61 +112,61 @@ void error_redirect( const gchar *domain, GLogLevelFlags log_level, const gchar
 	}
 
 	if ( domain ) {
-		strcpy( buf, domain );
+        buf.copy(domain);
 	}
 	else{
-		strcpy( buf, "**" );
+        buf.copy("**");
 	}
-	strcat( buf, "-" );
+	strcat( buf.mut(), "-" );
 
 	switch ( log_level )
 	{
 	case G_LOG_LEVEL_ERROR:
 		if ( in_recursion ) {
-			strcat( buf, "ERROR (recursed) **: " );
+			strcat( buf.mut(), "ERROR (recursed) **: " );
 		}
 		else{
-			strcat( buf, "ERROR **: " );
+			strcat( buf.mut(), "ERROR **: " );
 		}
 		break;
 	case G_LOG_LEVEL_CRITICAL:
 		if ( in_recursion ) {
-			strcat( buf, "CRITICAL (recursed) **: " );
+			strcat( buf.mut(), "CRITICAL (recursed) **: " );
 		}
 		else{
-			strcat( buf, "CRITICAL **: " );
+			strcat( buf.mut(), "CRITICAL **: " );
 		}
 		break;
 	case G_LOG_LEVEL_WARNING:
 		if ( in_recursion ) {
-			strcat( buf, "WARNING (recursed) **: " );
+			strcat( buf.mut(), "WARNING (recursed) **: " );
 		}
 		else{
-			strcat( buf, "WARNING **: " );
+			strcat( buf.mut(), "WARNING **: " );
 		}
 		break;
 	case G_LOG_LEVEL_MESSAGE:
 		if ( in_recursion ) {
-			strcat( buf, "Message (recursed): " );
+			strcat( buf.mut(), "Message (recursed): " );
 		}
 		else{
-			strcat( buf, "Message: " );
+			strcat( buf.mut(), "Message: " );
 		}
 		break;
 	case G_LOG_LEVEL_INFO:
 		if ( in_recursion ) {
-			strcat( buf, "INFO (recursed): " );
+			strcat( buf.mut(), "INFO (recursed): " );
 		}
 		else{
-			strcat( buf, "INFO: " );
+			strcat( buf.mut(), "INFO: " );
 		}
 		break;
 	case G_LOG_LEVEL_DEBUG:
 		if ( in_recursion ) {
-			strcat( buf, "DEBUG (recursed): " );
+			strcat( buf.mut(), "DEBUG (recursed): " );
 		}
 		else{
-			strcat( buf, "DEBUG: " );
+			strcat( buf.mut(), "DEBUG: " );
 		}
 		break;
 	default:
@@ -174,10 +174,10 @@ void error_redirect( const gchar *domain, GLogLevelFlags log_level, const gchar
 		 * try to make the best out of it.
 		 */
 		if ( in_recursion ) {
-			strcat( buf, "LOG (recursed:" );
+			strcat( buf.mut(), "LOG (recursed:" );
 		}
 		else{
-			strcat( buf, "LOG (" );
+			strcat( buf.mut(), "LOG (" );
 		}
 		if ( log_level ) {
 			gchar string[] = "0x00): ";
@@ -192,19 +192,19 @@ void error_redirect( const gchar *domain, GLogLevelFlags log_level, const gchar
 				*p += 'A' - '9' - 1;
 			}
 
-			strcat( buf, string );
+			strcat( buf.mut(), string );
 		}
 		else{
-			strcat( buf, "): " );
+			strcat( buf.mut(), "): " );
 		}
 	}
 
-	strcat( buf, message );
+	strcat( buf.mut(), message );
 	if ( is_fatal ) {
-		strcat( buf, "\naborting...\n" );
+		strcat( buf.mut(), "\naborting...\n" );
 	}
 	else{
-		strcat( buf, "\n" );
+		strcat( buf.mut(), "\n" );
 	}
 
 	// spam it...
@@ -350,15 +350,16 @@ bool check_version_file( const char* filename, const char* version ){
 	TextFileInputStream file( filename );
 	if ( !file.failed() ) {
 		auto buf = u::buffer<10>();
-		buf[file.read( buf, 9 )] = '\0';
+        auto mut_buf = buf.mut();
+        mut_buf[file.read(mut_buf, 9 )] = '\0';
 
 		// chomp it (the hard way)
 		int chomp = 0;
-		while ( buf[chomp] >= '0' && buf[chomp] <= '9' )
+		while (mut_buf[chomp] >= '0' && mut_buf[chomp] <= '9' )
 			chomp++;
-		buf[chomp] = '\0';
+		mut_buf[chomp] = '\0';
 
-		return string_equal( buf, version );
+		return string_equal(mut_buf, version );
 	}
 	return false;
 }
diff --git a/radiant/mainframe.cpp b/radiant/mainframe.cpp
index 02c8c9b3..de092b84 100644
--- a/radiant/mainframe.cpp
+++ b/radiant/mainframe.cpp
@@ -530,8 +530,8 @@ CLoadModule( const char* path ) : m_path( path ){
 void operator()( const char* name ) const {
 	auto fullname = u::buffer<1024>();
 	ASSERT_MESSAGE( strlen( m_path ) + strlen( name ) < 1024, "" );
-	strcpy( fullname, m_path );
-	strcat( fullname, name );
+	fullname.copy(m_path);
+	strcat( fullname.mut(), name );
 	globalOutputStream() << "Found '" << fullname << "'\n";
 	GlobalModuleServer_loadModule( fullname );
 }
diff --git a/radiant/map.cpp b/radiant/map.cpp
index 2f42496f..c94d8efc 100644
--- a/radiant/map.cpp
+++ b/radiant/map.cpp
@@ -153,7 +153,7 @@ void detach( const NameCallback& setName, const NameCallbackCallback& detachObse
 
 void makeUnique( const char* name, const NameCallback& setName ) const {
 	auto buffer = u::buffer<1024>();
-	name_write( buffer, m_uniqueNames.make_unique( name_read( name ) ) );
+	name_write( buffer.mut(), m_uniqueNames.make_unique( name_read( name ) ) );
 	setName( buffer );
 }
 
@@ -175,7 +175,7 @@ void mergeNames( const BasicNamespace& other ) const {
 		uniqueNames.insert( uniqueName );
 
 		auto buffer = u::buffer<1024>();
-		name_write( buffer, uniqueName );
+		name_write( buffer.mut(), uniqueName );
 
 		//globalOutputStream() << "renaming " << makeQuoted((*i).first.c_str()) << " to " << makeQuoted(buffer) << "\n";
 
@@ -879,7 +879,7 @@ void DoMapInfo(){
 		for ( EntityBreakdown::iterator i = entitymap.begin(); i != entitymap.end(); ++i )
 		{
 			auto tmp = u::buffer<16>();
-			sprintf( tmp, "%u", Unsigned( ( *i ).second ) );
+			tmp.sprintf( "%u", Unsigned( ( *i ).second ) );
 			GtkTreeIter iter;
 			gtk_list_store_append( GTK_LIST_STORE( EntityBreakdownWalker ), &iter );
 			gtk_list_store_set( GTK_LIST_STORE( EntityBreakdownWalker ), &iter, 0, ( *i ).first.c_str(), 1, tmp, -1 );
@@ -889,9 +889,9 @@ void DoMapInfo(){
 	EntityBreakdownWalker.unref();
 
 	auto tmp = u::buffer<16>();
-	sprintf( tmp, "%u", Unsigned( g_brushCount.get() ) );
+    tmp.sprintf( "%u", Unsigned( g_brushCount.get() ) );
 	brushes_entry.text(tmp);
-	sprintf( tmp, "%u", Unsigned( g_entityCount.get() ) );
+    tmp.sprintf( "%u", Unsigned( g_entityCount.get() ) );
 	entities_entry.text(tmp);
 
 	modal_dialog_show( window, dialog );
@@ -1269,9 +1269,9 @@ void ConstructRegionStartpoint( scene::Node* startpoint, const Vector3& region_m
 
 	// write the info_playerstart
 	auto sTmp = u::buffer<1024>();
-	sprintf( sTmp, "%d %d %d", (int)vOrig[0], (int)vOrig[1], (int)vOrig[2] );
+	sTmp.sprintf( "%d %d %d", (int)vOrig[0], (int)vOrig[1], (int)vOrig[2] );
 	Node_getEntity( *startpoint )->setKeyValue( "origin", sTmp );
-	sprintf( sTmp, "%d", (int)Camera_getAngles( *g_pParentWnd->GetCamWnd() )[CAMERA_YAW] );
+	sTmp.sprintf( "%d", (int)Camera_getAngles( *g_pParentWnd->GetCamWnd() )[CAMERA_YAW] );
 	Node_getEntity( *startpoint )->setKeyValue( "angle", sTmp );
 }
 
@@ -2106,9 +2106,9 @@ void DoFind(){
 	int ent, br;
 
 	GetSelectionIndex( &ent, &br );
-	sprintf( buf, "%i", ent );
+	buf.sprintf( "%i", ent );
 	entity.text(buf);
-	sprintf( buf, "%i", br );
+	buf.sprintf( "%i", br );
 	brush.text(buf);
 
 	if ( modal_dialog_show( window, dialog ) == eIDOK ) {
diff --git a/radiant/mru.cpp b/radiant/mru.cpp
index 916ea842..8e287e81 100644
--- a/radiant/mru.cpp
+++ b/radiant/mru.cpp
@@ -144,7 +144,7 @@ void MRU_AddWidget( GtkMenuItem *widget, std::size_t pos ){
 
 void MRU_Activate( std::size_t index ){
 	auto text = u::buffer<1024>();
-	strcpy( text, MRU_GetText( index ) );
+	text.copy( MRU_GetText( index ) );
 
 	if ( file_readable( text ) ) { //\todo Test 'map load succeeds' instead of 'file is readable'.
 		MRU_AddFile( text );
diff --git a/radiant/patch.h b/radiant/patch.h
index bc98fabe..3cfd1ad2 100644
--- a/radiant/patch.h
+++ b/radiant/patch.h
@@ -806,8 +806,8 @@ void exportXML( XMLImporter& importer ){
 	{
 		auto width = u::buffer<16>();
 		auto height = u::buffer<16>();
-		sprintf( width, "%u", Unsigned( m_width ) );
-		sprintf( height, "%u", Unsigned( m_height ) );
+		width.sprintf( "%u", Unsigned( m_width ) );
+		height.sprintf( "%u", Unsigned( m_height ) );
 		StaticElement element( "matrix" );
 		element.insertAttribute( "width", width );
 		element.insertAttribute( "height", height );
diff --git a/radiant/patchdialog.cpp b/radiant/patchdialog.cpp
index 7c1e63a4..1faadd93 100644
--- a/radiant/patchdialog.cpp
+++ b/radiant/patchdialog.cpp
@@ -1080,7 +1080,7 @@ void PatchInspector::GetPatchInfo(){
 			for ( std::size_t i = 0; i < m_countRows; ++i )
 			{
 				auto buffer = u::buffer<16>();
-				sprintf( buffer, "%u", Unsigned( i ) );
+				buffer.sprintf( "%u", Unsigned( i ) );
 				gtk_combo_box_text_append_text( m_pRowCombo, buffer );
 			}
 
@@ -1099,7 +1099,7 @@ void PatchInspector::GetPatchInfo(){
 			for ( std::size_t i = 0; i < m_countCols; ++i )
 			{
 				auto buffer = u::buffer<16>();
-				sprintf( buffer, "%u", Unsigned( i ) );
+				buffer.sprintf( "%u", Unsigned( i ) );
 				gtk_combo_box_text_append_text( m_pColCombo, buffer );
 			}
 
diff --git a/radiant/qe3.cpp b/radiant/qe3.cpp
index 717c3c84..ed47fed4 100644
--- a/radiant/qe3.cpp
+++ b/radiant/qe3.cpp
@@ -120,7 +120,7 @@ int g_numentities = 0;
 
 void QE_UpdateStatusBar(){
 	auto buffer = u::buffer<128>();
-	sprintf( buffer, "Brushes: %d Entities: %d", g_numbrushes, g_numentities );
+	buffer.sprintf( "Brushes: %d Entities: %d", g_numbrushes, g_numentities );
 	g_pParentWnd->SetStatusText( g_pParentWnd->m_brushcount_status, buffer );
 }
 
diff --git a/radiant/textures.cpp b/radiant/textures.cpp
index 3b96fbbf..d5b82429 100644
--- a/radiant/textures.cpp
+++ b/radiant/textures.cpp
@@ -141,9 +141,10 @@ ETexturesMode g_texture_mode = eTextures_LINEAR_MIPMAP_LINEAR;
 u::BufferVal<256> g_gammatable;
 void ResampleGamma( float fGamma ){
 	int i,inf;
-	if ( fGamma == 1.0 ) {
+	auto buf = g_gammatable.mut();
+	if (fGamma == 1.0 ) {
 		for ( i = 0; i < 256; i++ )
-			g_gammatable[i] = i;
+			buf[i] = i;
 	}
 	else
 	{
@@ -156,7 +157,7 @@ void ResampleGamma( float fGamma ){
 			if ( inf > 255 ) {
 				inf = 255;
 			}
-			g_gammatable[i] = inf;
+			buf[i] = inf;
 		}
 	}
 }
diff --git a/radiant/texwindow.cpp b/radiant/texwindow.cpp
index 0f25c594..f0efcbf1 100644
--- a/radiant/texwindow.cpp
+++ b/radiant/texwindow.cpp
@@ -1572,13 +1572,13 @@ void TreeView_onRowActivated( GtkTreeView* treeview, GtkTreePath* path, GtkTreeV
 
 		gchar* buffer;
 		gtk_tree_model_get( model, &iter, 0, &buffer, -1 );
-		strcpy( dirName, buffer );
+		dirName.copy(buffer);
 		g_free( buffer );
 
 		g_TextureBrowser.m_searchedTags = false;
 
 		if ( !TextureBrowser_showWads() ) {
-			strcat( dirName, "/" );
+			strcat( dirName.mut(), "/" );
 		}
 
 		ScopeDisableScreenUpdates disableScreenUpdates( dirName, "Loading Textures" );
@@ -1857,8 +1857,8 @@ void TextureBrowser_searchTags(){
 	gtk_tree_selection_selected_foreach( selection, (GtkTreeSelectionForeachFunc)TextureBrowser_tagMoveHelper, &selected );
 
 	if ( selected != NULL ) {
-		strcpy( buffer, "/root/*/*[tag='" );
-		strcpy( tags_searched, "[TAGS] " );
+		buffer.copy( "/root/*/*[tag='" );
+		tags_searched.copy( "[TAGS] " );
 
 		for ( node = selected; node != NULL; node = node->next )
 		{
@@ -1870,17 +1870,17 @@ void TextureBrowser_searchTags(){
 				if ( gtk_tree_model_get_iter( GTK_TREE_MODEL( g_TextureBrowser.m_all_tags_list ), &iter, path ) ) {
 					gtk_tree_model_get( GTK_TREE_MODEL( g_TextureBrowser.m_all_tags_list ), &iter, TAG_COLUMN, &tag, -1 );
 
-					strcat( buffer, tag );
-					strcat( tags_searched, tag );
+					strcat( buffer.mut(), tag );
+					strcat( tags_searched.mut(), tag );
 					if ( node != g_slist_last( node ) ) {
-						strcat( buffer, "' and tag='" );
-						strcat( tags_searched, ", " );
+						strcat( buffer.mut(), "' and tag='" );
+						strcat( tags_searched.mut(), ", " );
 					}
 				}
 			}
 		}
 
-		strcat( buffer, "']" );
+		strcat( buffer.mut(), "']" );
 
 		g_slist_foreach( selected, (GFunc)gtk_tree_row_reference_free, NULL );
 
@@ -2429,10 +2429,10 @@ void TextureBrowser_RefreshShaders(){
 
 		gchar* buffer;
 		gtk_tree_model_get( model, &iter, 0, &buffer, -1 );
-		strcpy( dirName, buffer );
+        dirName.copy( buffer );
 		g_free( buffer );
 		if ( !TextureBrowser_showWads() ) {
-			strcat( dirName, "/" );
+			strcat( dirName.mut(), "/" );
 		}
 		TextureBrowser_ShowDirectory( GlobalTextureBrowser(), dirName );
 		TextureBrowser_queueDraw( GlobalTextureBrowser() );
diff --git a/radiant/view.cpp b/radiant/view.cpp
index 38b50538..b6b7912d 100644
--- a/radiant/view.cpp
+++ b/radiant/view.cpp
@@ -48,7 +48,7 @@ void Cull_ResetStats(){
 
 const char* Cull_GetStats(){
 #if defined( DEBUG_CULLING )
-	sprintf( g_cull_stats, "dots: %d | planes %d + %d | bboxs %d + %d", g_count_dots, g_count_planes, g_count_oriented_planes, g_count_bboxs, g_count_oriented_bboxs );
+	g_cull_stats.sprintf( "dots: %d | planes %d + %d | bboxs %d + %d", g_count_dots, g_count_planes, g_count_oriented_planes, g_count_bboxs, g_count_oriented_bboxs );
 	return g_cull_stats;
 #else
 	return "";
diff --git a/radiant/watchbsp.cpp b/radiant/watchbsp.cpp
index 6ac7f553..e8107018 100644
--- a/radiant/watchbsp.cpp
+++ b/radiant/watchbsp.cpp
@@ -405,7 +405,7 @@ static void saxWarning( void *ctx, const char *msg, ... ){
 	va_list args;
 
 	va_start( args, msg );
-	vsprintf( saxMsgBuffer, msg, args );
+	vsprintf( saxMsgBuffer.mut(), msg, args );
 	va_end( args );
 	globalOutputStream() << "XML warning: " << saxMsgBuffer << "\n";
 }
@@ -415,7 +415,7 @@ static void saxError( void *ctx, const char *msg, ... ){
 	va_list args;
 
 	va_start( args, msg );
-	vsprintf( saxMsgBuffer, msg, args );
+	vsprintf( saxMsgBuffer.mut(), msg, args );
 	va_end( args );
 	globalErrorStream() << "XML error: " << saxMsgBuffer << "\n";
 }
@@ -426,7 +426,7 @@ static void saxFatal( void *ctx, const char *msg, ... ){
 	va_list args;
 
 	va_start( args, msg );
-	vsprintf( buffer, msg, args );
+	vsprintf( buffer.mut(), msg, args );
 	va_end( args );
 	globalErrorStream() << "XML fatal error: " << buffer << "\n";
 }
diff --git a/radiant/xywindow.cpp b/radiant/xywindow.cpp
index 4e6b531e..4f1d4082 100644
--- a/radiant/xywindow.cpp
+++ b/radiant/xywindow.cpp
@@ -1439,9 +1439,9 @@ void XYWnd::XY_LoadBackgroundImage( const char *name ){
 	}
 
 	auto fileNameWithoutExt = u::buffer<512>();
-	strncpy( fileNameWithoutExt, relative, sizeof( fileNameWithoutExt ) - 1 );
-	fileNameWithoutExt[512 - 1] = '\0';
-	fileNameWithoutExt[strlen( fileNameWithoutExt ) - 4] = '\0';
+	fileNameWithoutExt.copy(relative);
+	fileNameWithoutExt.terminate();
+	fileNameWithoutExt.mut()[fileNameWithoutExt.strlen() - 4] = '\0';
 
 	Image *image = QERApp_LoadImage( 0, fileNameWithoutExt );
 	if ( !image ) {
@@ -1718,12 +1718,12 @@ void XYWnd::XY_DrawGrid( void ) {
 		float offy = m_vOrigin[nDim1] - w +  4                                            / m_fScale;
 		for ( x = xb - fmod( xb, stepx ); x <= xe ; x += stepx ) {
 			glRasterPos2f( x, offx );
-			sprintf( text, "%g", x );
+			text.sprintf( "%g", x );
 			GlobalOpenGL().drawString( text );
 		}
 		for ( y = yb - fmod( yb, stepy ); y <= ye ; y += stepy ) {
 			glRasterPos2f( offy, y );
-			sprintf( text, "%g", y );
+			text.sprintf( "%g", y );
 			GlobalOpenGL().drawString( text );
 		}
 
@@ -1847,7 +1847,7 @@ void XYWnd::XY_DrawBlockGrid(){
 			for ( y = yb ; y < ye ; y += g_xywindow_globals_private.blockSize )
 			{
 				glRasterPos2f( x + ( g_xywindow_globals_private.blockSize / 2 ), y + ( g_xywindow_globals_private.blockSize / 2 ) );
-				sprintf( text, "%i,%i",(int)floor( x / g_xywindow_globals_private.blockSize ), (int)floor( y / g_xywindow_globals_private.blockSize ) );
+                text.sprintf( "%i,%i",(int)floor( x / g_xywindow_globals_private.blockSize ), (int)floor( y / g_xywindow_globals_private.blockSize ) );
 				GlobalOpenGL().drawString( text );
 			}
 	}