Rewrote the string class with a simpler version. The old one was more than probably leaking water like a boat with an elephant on board...

Fri, 10 May 2013 17:39:56 +0300

author
Santeri Piippo <crimsondusk64@gmail.com>
date
Fri, 10 May 2013 17:39:56 +0300
changeset 189
ac2d3e8dd110
parent 188
4e686b771996
child 190
82f784cf2ce5

Rewrote the string class with a simpler version. The old one was more than probably leaking water like a boat with an elephant on board...

src/addObjectDialog.cpp file | annotate | diff | comparison | revisions
src/colorSelectDialog.cpp file | annotate | diff | comparison | revisions
src/colors.cpp file | annotate | diff | comparison | revisions
src/colors.h file | annotate | diff | comparison | revisions
src/common.h file | annotate | diff | comparison | revisions
src/config.cpp file | annotate | diff | comparison | revisions
src/config.h file | annotate | diff | comparison | revisions
src/configDialog.cpp file | annotate | diff | comparison | revisions
src/file.cpp file | annotate | diff | comparison | revisions
src/file.h file | annotate | diff | comparison | revisions
src/gldraw.cpp file | annotate | diff | comparison | revisions
src/gui.cpp file | annotate | diff | comparison | revisions
src/gui.h file | annotate | diff | comparison | revisions
src/gui_editactions.cpp file | annotate | diff | comparison | revisions
src/historyDialog.cpp file | annotate | diff | comparison | revisions
src/ldtypes.cpp file | annotate | diff | comparison | revisions
src/main.cpp file | annotate | diff | comparison | revisions
src/misc.cpp file | annotate | diff | comparison | revisions
src/misc.h file | annotate | diff | comparison | revisions
src/str.cpp file | annotate | diff | comparison | revisions
src/str.h file | annotate | diff | comparison | revisions
src/string.cpp file | annotate | diff | comparison | revisions
src/string.h file | annotate | diff | comparison | revisions
src/types.h file | annotate | diff | comparison | revisions
--- a/src/addObjectDialog.cpp	Thu May 09 17:03:44 2013 +0300
+++ b/src/addObjectDialog.cpp	Fri May 10 17:39:56 2013 +0300
@@ -307,7 +307,7 @@
 	button->setIcon (getIcon ("palette"));
 	button->setAutoFillBackground (true);
 	button->setStyleSheet (
-		fmt ("background-color: %s", getColor (color)->zColorString.chars()).chars()
+		fmt ("background-color: %s", getColor (color)->hexcode.chars()).chars()
 	);
 }
 
@@ -387,7 +387,7 @@
 	
 	matrix<3> transform = g_identity;
 	if (type == LDObject::Subfile || type == LDObject::Radial) {
-		vector<str> matrixstrvals = str (dlg.le_matrix->text ()).split (" ", true);
+		vector<str> matrixstrvals = str (dlg.le_matrix->text ()).split (" ");
 		
 		if (matrixstrvals.size () == 9) {
 			double matrixvals[9];
--- a/src/colorSelectDialog.cpp	Thu May 09 17:03:44 2013 +0300
+++ b/src/colorSelectDialog.cpp	Fri May 10 17:39:56 2013 +0300
@@ -108,7 +108,7 @@
 		const double y = (i / g_dNumColumns) * g_dSquareSize;
 		const double w = (g_dSquareSize) - (fPenWidth / 2);
 		
-		QColor col = meta->qColor;
+		QColor col = meta->faceColor;
 		
 		if (i == maincolor) {
 			// Use the user preferences for main color here
@@ -142,7 +142,7 @@
 	}
 	
 	lb_colorInfo->setText (fmt ("%d - %s",
-		selColor, col->zName.chars()));
+		selColor, col->name.chars()));
 }
 
 // =============================================================================
--- a/src/colors.cpp	Thu May 09 17:03:44 2013 +0300
+++ b/src/colors.cpp	Fri May 10 17:39:56 2013 +0300
@@ -23,31 +23,25 @@
 #include <qcolor.h>
 
 static color* g_LDColors[MAX_COLORS];
-static bool g_bColorsInit = false;
 
 void initColors () {
-	if (g_bColorsInit)
-		return;
-	
-	logf ("%s: initializing color information.\n", __func__);
+	printf ("%s: initializing color information.\n", __func__);
 	
 	color* col;
 	
 	// Always make sure there's 16 and 24 available. They're special like that.
 	col = new color;
-	col->zColorString = "#AAAAAA";
-	col->qColor = col->zColorString.chars ();
-	col->qEdge = Qt::black;
+	col->hexcode = "#AAAAAA";
+	col->faceColor = col->hexcode.chars ();
+	col->edgeColor = Qt::black;
 	g_LDColors[maincolor] = col;
 	
 	col = new color;
-	col->zColorString = "#000000";
-	col->qEdge = col->qColor = Qt::black;
+	col->hexcode = "#000000";
+	col->edgeColor = col->faceColor = Qt::black;
 	g_LDColors[edgecolor] = col;
 	
 	parseLDConfig ();
-	
-	g_bColorsInit = true;
 }
 
 // =============================================================================
@@ -64,26 +58,12 @@
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-static bool parseLDConfigTag (StringParser& pars, char const* sTag, str& zVal) {
-	short dPos;
-	if (!pars.findToken (dPos, sTag, 1))
+static bool parseLDConfigTag (StringParser& pars, char const* tag, str& val) {
+	short pos;
+	if (!pars.findToken (pos, tag, 1))
 		return false;
 	
-	return pars.getToken (zVal, dPos + 1);
-}
-
-// =============================================================================
-// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-// =============================================================================
-short color::index () {
-	short idx = 0;
-	for (color* it : g_LDColors) {
-		if (it == this)
-			return idx;
-		idx++;
-	}
-	
-	return -1;
+	return pars.getToken (val, pos + 1);
 }
 
 // =============================================================================
@@ -104,18 +84,16 @@
 	
 	// Even though LDConfig.ldr is technically an LDraw file, parsing it as one
 	// would be overkill by any standard.
-	char line[1024];
-	while (fgets (line, sizeof line, fp)) {
-		if (strlen (line) == 0 || line[0] != '0')
+	char buf[1024];
+	while (fgets (buf, sizeof buf, fp)) {
+		if (strlen (buf) == 0 || buf[0] != '0')
 			continue; // empty or illogical
 		
-		str zLine = line;
-		zLine.replace ("\n", "");
-		zLine.replace ("\r", "");
+		str line = str (buf).strip ({'\n', '\r'});
+		StringParser pars (line, ' ');
 		
-		StringParser pars (zLine, ' ');
 		short code = 0, alpha = 255;
-		str name, colname, edge, value;
+		str name, facename, edgename, valuestr;
 		
 		// Check 0 !COLOUR, parse the name
 		if (!pars.tokenCompare (0, "0") || !pars.tokenCompare (1, "!COLOUR") || !pars.getToken (name, 2))
@@ -125,46 +103,40 @@
 		name.replace ("_", " ");
 		
 		// get the CODE tag
-		if (!parseLDConfigTag (pars, "CODE", value))
+		if (!parseLDConfigTag (pars, "CODE", valuestr))
 			continue;
 		
 		// Ensure that the code is within range. must be within 0 - 512
-		code = atoi (value);
+		code = atoi (valuestr);
 		if (code < 0 || code >= 512)
 			continue;
 		
-		// Don't let LDConfig.ldr override the special colors 16 and 24. However,
-		// do take the name it gives for the color
-		if (code == maincolor || code == edgecolor) {
-			g_LDColors[code]->zName = name;
-			continue;
-		}
-		
 		// VALUE tag
-		if (!parseLDConfigTag (pars, "VALUE", colname))
+		if (!parseLDConfigTag (pars, "VALUE", facename))
 			continue;
 		
 		// EDGE tag
-		if (!parseLDConfigTag (pars, "EDGE", edge))
+		if (!parseLDConfigTag (pars, "EDGE", edgename))
 			continue;
 		
 		// Ensure that our colors are correct
-		QColor qColor (colname.chars()),
-			qEdge (edge.chars());
+		QColor faceColor (facename.chars()),
+			edgeColor (edgename.chars());
 		
-		if (!qColor.isValid () || !qEdge.isValid ())
+		if (!faceColor.isValid () || !edgeColor.isValid ())
 			continue;
 		
 		// Parse alpha if given.
-		if (parseLDConfigTag (pars, "ALPHA", value))
-			alpha = clamp<short> (atoi (value), 0, 255);
+		if (parseLDConfigTag (pars, "ALPHA", valuestr))
+			alpha = clamp<short> (atoi (valuestr), 0, 255);
 		
 		color* col = new color;
-		col->zName = name;
-		col->qColor = qColor;
-		col->qEdge = qEdge;
-		col->zColorString = colname;
-		col->qColor.setAlpha (alpha);
+		col->name = name;
+		col->faceColor = faceColor;
+		col->edgeColor = edgeColor;
+		col->hexcode = facename;
+		col->faceColor.setAlpha (alpha);
+		col->index = code;
 		
 		g_LDColors[code] = col;
 	}
--- a/src/colors.h	Thu May 09 17:03:44 2013 +0300
+++ b/src/colors.h	Fri May 10 17:39:56 2013 +0300
@@ -26,18 +26,11 @@
 
 class color {
 public:
-	str zName, zColorString;
-	QColor qColor, qEdge;
-	
-	short index ();
+	str name, hexcode;
+	QColor faceColor, edgeColor;
+	short index;
 };
 
-typedef struct {
-	const short dIndex;
-	const char* sName, *sColor;
-	const float fAlpha;
-} TemporaryColorMeta;
-
 void initColors ();
 void parseLDConfig ();
 uchar luma (QColor& col);
--- a/src/common.h	Thu May 09 17:03:44 2013 +0300
+++ b/src/common.h	Fri May 10 17:39:56 2013 +0300
@@ -29,7 +29,7 @@
 #include <vector>
 #include <stdint.h>
 #include <stdarg.h>
-#include "str.h"
+#include "string.h"
 #include "config.h"
 #include "types.h"
 
@@ -43,6 +43,14 @@
 // ============---
 // #define RELEASE
 
+#ifndef RELEASE
+# define devf(...) doDevf (__func__, __VA_ARGS__);
+#else
+# define devf(...)
+#endif // RELEASE
+
+void doDevf (const char* func, const char* fmtstr, ...);
+
 // Version string identifier
 static const str versionString = fmt ("%d.%d", VERSION_MAJOR, VERSION_MINOR);
 
@@ -147,15 +155,6 @@
 // logf is defined in main.cpp
 void logf (const char* fmtstr, ...) FORMAT_PRINTF (1, 2);
 void logf (LogType type, const char* fmtstr, ...) FORMAT_PRINTF (2, 3);
-void warnf (const char* fmtstr, ...) FORMAT_PRINTF (1, 2);
-void errf (const char* fmtstr, ...) FORMAT_PRINTF (1, 2);
-
-#ifndef RELEASE
-void devf (const char* fmtstr, ...);
-#else
-# define devf(...)
-#endif // RELEASE
-
 // -----------------------------------------------------------------------------
 // Vertex at (0, 0, 0)
 extern const vertex g_origin;
--- a/src/config.cpp	Thu May 09 17:03:44 2013 +0300
+++ b/src/config.cpp	Fri May 10 17:39:56 2013 +0300
@@ -22,11 +22,12 @@
 #include <time.h>
 #include <QDir>
 #include "common.h"
-#include "str.h"
 #include "config.h"
 
 std::vector<config*> g_configPointers;
 
+
+
 // =============================================================================
 const char* g_WeekdayNames[7] = {
 	"Sunday",
@@ -115,9 +116,9 @@
 		// Trim the crap off the end
 		while (~valstring) {
 			char c = valstring[~valstring - 1];
-			if (c <= 32 || c >= 127)
+			if (c <= 32 || c >= 127) {
 				valstring -= 1;
-			else
+			} else
 				break;
 		}
 		
@@ -164,7 +165,7 @@
 	va_list va;
 	
 	va_start (va, fmt);
-	char* buf = vdynformat (fmt, va, 256);
+	char* buf = dynafmt (fmt, va, 256);
 	va_end (va);
 	
 	size_t len = fwrite (buf, 1, strlen (buf), fp);
@@ -216,29 +217,23 @@
 		case CONFIG_int:
 			valstring.format ("%d", static_cast<intconfig*> (cfg)->value);
 			break;
+		
 		case CONFIG_str:
 			valstring = static_cast<strconfig*> (cfg)->value;
 			break;
+		
 		case CONFIG_float:
-			valstring.format ("%f", static_cast<floatconfig*> (cfg)->value);
-			
-			// Trim any trailing zeros
-			if (valstring.first (".") != -1) {
-				while (valstring[~valstring - 1] == '0')
-					valstring -= 1;
-				
-				// But don't trim the only one out...
-				if (valstring[~valstring - 1] == '.')
-					valstring += '0';
-			}
-			
+			valstring.format ("%s", ftoa (static_cast<floatconfig*> (cfg)->value).c ());
 			break;
+		
 		case CONFIG_bool:
 			valstring = (static_cast<boolconfig*> (cfg)->value) ? "true" : "false";
 			break;
+		
 		case CONFIG_keyseq:
 			valstring = static_cast<keyseqconfig*> (cfg)->value.toString ();
 			break;
+		
 		default:
 			break;
 		}
@@ -265,12 +260,12 @@
 str config::filepath () {
 	str path;
 	path.format ("%s%s.cfg", dirpath ().chars (),
-		str (APPNAME).tolower ().chars ());
+		str (APPNAME).lower ().chars ());
 	return path;
 }
 
 // =============================================================================
 str config::dirpath () {
 	return fmt ("%s/.%s/", qchars (QDir::homePath ()),
-		str (APPNAME).tolower ().chars ());
+		str (APPNAME).lower ().chars ());
 }
\ No newline at end of file
--- a/src/config.h	Thu May 09 17:03:44 2013 +0300
+++ b/src/config.h	Fri May 10 17:39:56 2013 +0300
@@ -20,7 +20,6 @@
 #define CONFIG_H
 
 #include "common.h"
-#include "str.h"
 
 // =============================================================================
 #include <QString>
@@ -168,25 +167,19 @@
 public:
 	IMPLEMENT_CONFIG (str)
 	
-	DEFINE_ALL_COMPARE_OPERATORS (str)
-	DEFINE_BINARY_OPERATOR (str, -)
-	DEFINE_BINARY_OPERATOR (str, *)
-	DEFINE_UNARY_OPERATOR (str, !)
+	DEFINE_COMPARE_OPERATOR (str, ==)
+	DEFINE_COMPARE_OPERATOR (str, !=)
 	DEFINE_ASSIGN_OPERATOR (str, =)
 	DEFINE_ASSIGN_OPERATOR (str, +=)
-	DEFINE_ASSIGN_OPERATOR (str, -=)
-	DEFINE_ASSIGN_OPERATOR (str, *=)
-	DEFINE_CAST_OPERATOR (char*)
+	DEFINE_CAST_OPERATOR (const char*)
 	
 	char operator[] (size_t n) {
 		return value[n];
 	}
 	
-#ifdef CONFIG_WITH_QT
 	operator QString () {
 		return QString (value.chars());
 	}
-#endif // CONFIG_WITH_QT
 };
 
 // =============================================================================
--- a/src/configDialog.cpp	Thu May 09 17:03:44 2013 +0300
+++ b/src/configDialog.cpp	Fri May 10 17:39:56 2013 +0300
@@ -289,7 +289,7 @@
 	for (int i = 0; i < g_NumGrids; ++i) {
 		// Icon
 		lb_gridIcons[i] = new QLabel;
-		lb_gridIcons[i]->setPixmap (getIcon (fmt ("grid-%s", str (g_GridInfo[i].name).tolower ().chars ())));
+		lb_gridIcons[i]->setPixmap (getIcon (fmt ("grid-%s", str (g_GridInfo[i].name).lower ().chars ())));
 		
 		// Text label
 		lb_gridLabels[i] = new QLabel (fmt ("%s:", g_GridInfo[i].name));
@@ -392,7 +392,7 @@
 				item->setText ("[[unknown color]]");
 				item->setIcon (getIcon ("error"));
 			} else {
-				item->setText (col->zName);
+				item->setText (col->name);
 				item->setIcon (makeColorIcon (col, 16));
 			}
 		}
@@ -427,7 +427,7 @@
 			return; // don't color separators
 	}
 	
-	short dDefault = entry ? entry->col->index () : -1;
+	short dDefault = entry ? entry->col->index : -1;
 	short dValue;
 	
 	if (ColorSelectDialog::staticDialog (dValue, dDefault, this) == false)
@@ -674,7 +674,7 @@
 		if (entry.bSeparator)
 			val += '|';
 		else
-			val.appendformat ("%d", entry.col->index ());
+			val += fmt ("%d", entry.col->index);
 	}
 	
 	return val;
--- a/src/file.cpp	Thu May 09 17:03:44 2013 +0300
+++ b/src/file.cpp	Fri May 10 17:39:56 2013 +0300
@@ -113,41 +113,39 @@
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-FILE* openLDrawFile (str path, bool bSubDirectories) {
-	str zTruePath = path;
-	
+FILE* openLDrawFile (str relpath, bool subdirs) {
 #ifndef WIN32
-	zTruePath.replace ("\\", "/");
+	relpath.replace ("\\", "/");
 #endif // WIN32
 	
-	FILE* fp = fopen (path.chars (), "r");
-	str zFilePath;
+	printf ("Trying %s\n", relpath.chars ());
+	FILE* fp = fopen (relpath.chars (), "r");
+	str fullPath;
 	
 	if (fp != null)
 		return fp;
 	
 	if (~io_ldpath.value) {
 		// Try with just the LDraw path first
-		zFilePath = fmt ("%s" DIRSLASH "%s",
-			io_ldpath.value.chars(), zTruePath.chars());
-		logf ("Trying %s\n", zFilePath.chars());
+		fullPath = fmt ("%s" DIRSLASH "%s", io_ldpath.value.chars(), relpath.chars());
+		printf ("Trying %s\n", fullPath.chars());
 		
-		fp = fopen (zFilePath, "r");
+		fp = fopen (fullPath, "r");
 		if (fp != null)
 			return fp;
 		
-		if (bSubDirectories) {
+		if (subdirs) {
 			char const* saSubdirectories[] = {
 				"parts",
 				"p",
 			};
 			
 			for (char const* sSubdir : saSubdirectories) {
-				zFilePath = fmt ("%s" DIRSLASH "%s" DIRSLASH "%s",
-					io_ldpath.value.chars(), sSubdir, zTruePath.chars());
-				printf ("try %s\n", zFilePath.chars());
+				fullPath = fmt ("%s" DIRSLASH "%s" DIRSLASH "%s",
+					io_ldpath.value.chars(), sSubdir, relpath.chars());
+				printf ("Trying %s\n", fullPath.chars());
 				
-				fp = fopen (zFilePath.chars (), "r");
+				fp = fopen (fullPath.chars (), "r");
 				
 				if (fp)
 					return fp;
@@ -308,18 +306,24 @@
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-void addRecentFile (str zPath) {
-	long lPos = io_recentfiles.value.first (zPath);
+void addRecentFile (str path) {
+	size_t pos = io_recentfiles.value.first (path);
 	
 	// If this file already is in the list, pop it out.
-	if (lPos != -1) {
-		if (~io_recentfiles.value == ~zPath)
+	if (pos != npos) {
+		if (~io_recentfiles.value == ~path)
 			return; // only recent file - do nothing
 		
 		// Pop it out.
-		str zFront = io_recentfiles.value.substr (0, lPos);
-		str zBack = io_recentfiles.value.substr (lPos + ~zPath + 1, -1);
-		io_recentfiles.value = zFront + zBack;
+		str front = io_recentfiles.value.substr (0, pos);
+		str back;
+		
+		if (pos + ~path + 1 < io_recentfiles.value.len ())
+			back = io_recentfiles.value.substr (pos + ~path + 1, -1);
+		else
+			back = "";
+		
+		io_recentfiles.value = front + back;
 	}
 	
 	// If there's too many recent files, drop one out.
@@ -330,7 +334,7 @@
 	if (~io_recentfiles.value > 0)
 		io_recentfiles.value += "@";
 	
-	io_recentfiles += zPath;
+	io_recentfiles += path;
 	
 	config::save ();
 	g_win->updateRecentFilesMenu ();
@@ -402,12 +406,12 @@
 
 #define CHECK_TOKEN_COUNT(N) \
 	if (tokens.size() != N) \
-		return new LDGibberish (zLine, "Bad amount of tokens");
+		return new LDGibberish (line, "Bad amount of tokens");
 
 #define CHECK_TOKEN_NUMBERS(MIN,MAX) \
 	for (ushort i = MIN; i <= MAX; ++i) \
 		if (!isNumber (tokens[i])) \
-			return new LDGibberish (zLine, fmt ("Token #%u was `%s`, expected a number", \
+			return new LDGibberish (line, fmt ("Token #%u was `%s`, expected a number", \
 				(i + 1), tokens[i].chars()));
 
 // =============================================================================
@@ -429,8 +433,8 @@
 // =============================================================================
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
-LDObject* parseLine (str zLine) {
-	vector<str> tokens = zLine.split (" ", true);
+LDObject* parseLine (str line) {
+	vector<str> tokens = line.split (" ");
 	
 	if (!tokens.size ()) {
 		// Line was empty, or only consisted of whitespace
@@ -438,7 +442,7 @@
 	}
 	
 	if (~tokens[0] != 1)
-		return new LDGibberish (zLine, "Illogical line code");
+		return new LDGibberish (line, "Illogical line code");
 	
 	const char c = tokens[0][0];
 	switch (c - '0') {
@@ -490,14 +494,14 @@
 					LDRadial::Type eType = LDRadial::NumTypes;
 					
 					for (int i = 0; i < LDRadial::NumTypes; ++i) {
-						if (str (LDRadial::radialTypeName ((LDRadial::Type) i)).toupper ().strip (' ') == tokens[3]) {
+						if (str (LDRadial::radialTypeName ((LDRadial::Type) i)).upper ().strip (' ') == tokens[3]) {
 							eType = (LDRadial::Type) i;
 							break;
 						}
 					}
 					
 					if (eType == LDRadial::NumTypes)
-						return new LDGibberish (zLine, fmt ("Unknown radial type %s", tokens[3].chars ()));
+						return new LDGibberish (line, fmt ("Unknown radial type %s", tokens[3].chars ()));
 					
 					LDRadial* obj = new LDRadial;
 					
@@ -532,7 +536,7 @@
 			
 			// If we cannot open the file, mark it an error
 			if (!pFile)
-				return new LDGibberish (zLine, "Could not open referred file");
+				return new LDGibberish (line, "Could not open referred file");
 			
 			LDSubfile* obj = new LDSubfile;
 			obj->color = atol (tokens[1]);
@@ -605,7 +609,7 @@
 		}
 	
 	default: // Strange line we couldn't parse
-		return new LDGibberish (zLine, "Unknown line code number");
+		return new LDGibberish (line, "Unknown line code number");
 	}
 }
 
--- a/src/file.h	Thu May 09 17:03:44 2013 +0300
+++ b/src/file.h	Fri May 10 17:39:56 2013 +0300
@@ -21,7 +21,6 @@
 
 #include "common.h"
 #include "ldtypes.h"
-#include "str.h"
 
 namespace LDPaths {
 	void initPaths ();
@@ -96,7 +95,7 @@
 void closeAll ();
 
 // Parses a string line containing an LDraw object and returns the object parsed.
-LDObject* parseLine (str zLine);
+LDObject* parseLine (str line);
 
 // Retrieves the pointer to - or loads - the given subfile.
 OpenFile* loadSubfile (str zFile);
--- a/src/gldraw.cpp	Thu May 09 17:03:44 2013 +0300
+++ b/src/gldraw.cpp	Fri May 10 17:39:56 2013 +0300
@@ -112,7 +112,7 @@
 	// Init camera icons
 	for (const GLRenderer::Camera cam : g_Cameras) {
 		str iconname;
-		iconname.format ("camera-%s", str (g_CameraNames[cam]).tolower ().chars ());
+		iconname.format ("camera-%s", str (g_CameraNames[cam]).lower ().c ());
 		
 		CameraIcon* info = &g_CameraIcons[cam];
 		info->img = new QPixmap (getIcon (iconname));
@@ -249,7 +249,7 @@
 		qcol = getMainColor ();
 	else {
 		color* col = getColor (obj->color);
-		qcol = col->qColor;
+		qcol = col->faceColor;
 	}
 	
 	if (obj->color == edgecolor) {
@@ -257,7 +257,7 @@
 		color* col;
 		
 		if (!gl_blackedges && obj->parent != null && (col = getColor (obj->parent->color)) != null)
-			qcol = col->qEdge;
+			qcol = col->edgeColor;
 	}
 	
 	if (qcol.isValid () == false) {
--- a/src/gui.cpp	Thu May 09 17:03:44 2013 +0300
+++ b/src/gui.cpp	Fri May 10 17:39:56 2013 +0300
@@ -394,6 +394,7 @@
 			meta.push_back ({null, null, true});
 		} else {
 			color* col = getColor (atoi (colorname));
+			printf ("color: %d\n", atoi (colorname));
 			assert (col != null);
 			meta.push_back ({col, null, false});
 		}
@@ -427,7 +428,7 @@
 			QToolButton* colorButton = new QToolButton;
 			colorButton->setIcon (makeColorIcon (entry.col, gui_toolbar_iconsize));
 			colorButton->setIconSize (iconsize);
-			colorButton->setToolTip (entry.col->zName);
+			colorButton->setToolTip (entry.col->name);
 			
 			connect (colorButton, SIGNAL (clicked ()), this, SLOT (slot_quickColor ()));
 			m_colorToolBar->addWidget (colorButton);
@@ -611,7 +612,7 @@
 					ref->fileName.chars(), ref->pos.stringRep (true).chars());
 				
 				for (short i = 0; i < 9; ++i)
-					descr.appendformat ("%s%s",
+					descr += fmt ("%s%s",
 						ftoa (ref->transform[i]).chars(),
 						(i != 8) ? " " : "");
 				
@@ -632,9 +633,9 @@
 				descr.format ("%d / %d %s", pRad->segs, pRad->divs, pRad->radialTypeName());
 				
 				if (pRad->radType == LDRadial::Ring || pRad->radType == LDRadial::Cone)
-					descr.appendformat (" %d", pRad->ringNum);
+					descr += fmt (" %d", pRad->ringNum);
 				
-				descr.appendformat (" %s", pRad->pos.stringRep (true).chars ());
+				descr += fmt (" %s", pRad->pos.stringRep (true).chars ());
 			}
 			break;
 		
@@ -663,7 +664,7 @@
 			// list entry in said color.
 			color* col = getColor (obj->color);
 			if (col)
-				item->setForeground (col->qColor);
+				item->setForeground (col->faceColor);
 		}
 		
 		obj->qObjListEntry = item;
@@ -756,7 +757,7 @@
 	
 	std::vector<ulong> indices;
 	std::vector<short> colors;
-	short newColor = col->index ();
+	short newColor = col->index;
 	
 	for (LDObject* obj : m_sel) {
 		if (obj->color == -1)
@@ -1003,8 +1004,8 @@
 	QImage img (size, size, QImage::Format_ARGB32);
 	QPainter paint (&img);
 	
-	QColor col = colinfo->qColor;
-	if (colinfo->index () == maincolor) {
+	QColor col = colinfo->faceColor;
+	if (colinfo->index == maincolor) {
 		// Use the user preferences for main color here
 		col = gl_maincolor.value.chars ();
 		col.setAlpha (gl_maincolor_alpha * 255.0f);
@@ -1039,7 +1040,7 @@
 		
 		QIcon ico = makeColorIcon (col, 16);
 		box->addItem (ico, fmt ("[%d] %s (%lu object%s)",
-			pair.first, col->zName.chars (), pair.second, PLURAL (pair.second)));
+			pair.first, col->name.chars (), pair.second, PLURAL (pair.second)));
 		box->setItemData (row, pair.first);
 		
 		++row;
--- a/src/gui.h	Thu May 09 17:03:44 2013 +0300
+++ b/src/gui.h	Fri May 10 17:39:56 2013 +0300
@@ -152,13 +152,8 @@
 	void closeEvent (QCloseEvent* ev);
 	void logVA (LogType eType, const char* fmtstr, va_list va);
 	
-	friend void logf (const char* fmt, ...);
-	friend void logf (LogType eType, const char* fmt, ...);
-	friend void warnf (const char* fmt, ...);
-	friend void infof (const char* fmt, ...);
-	friend void succf (const char* fmt, ...);
-	friend void errf (const char* fmt, ...);
-	friend void devf (const char* fmt, ...);
+	friend void logf (const char* fmtstr, ...);
+	friend void logf (LogType type, const char* fmtstr, ...);
 	
 private:
 	GLRenderer* m_renderer;
--- a/src/gui_editactions.cpp	Thu May 09 17:03:44 2013 +0300
+++ b/src/gui_editactions.cpp	Fri May 10 17:39:56 2013 +0300
@@ -749,4 +749,11 @@
 
 MAKE_ACTION (intersector, "Intersector", "intersector", "Perform clipping between two input groups.", KEY (F5)) {
 	runIntersector ();
+}
+
+// =========================================================================================================================================
+// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+// =========================================================================================================================================
+MAKE_ACTION (replaceCoords, "Replace Coordinates", "replace-coords", "Find and replace coordinate values", CTRL (R)) {
+	QDialog dlg;
 }
\ No newline at end of file
--- a/src/historyDialog.cpp	Thu May 09 17:03:44 2013 +0300
+++ b/src/historyDialog.cpp	Fri May 10 17:39:56 2013 +0300
@@ -162,7 +162,7 @@
 				SetColorHistory* subentry = static_cast<SetColorHistory*> (entry);
 				ulong count = subentry->ulaIndices.size ();
 				text.format ("Set color of %lu objects to %d (%s)", count,
-					subentry->dNewColor, getColor (subentry->dNewColor)->zName.chars());
+					subentry->dNewColor, getColor (subentry->dNewColor)->name.chars());
 				
 				entryIcon = getIcon ("palette");
 			}
--- a/src/ldtypes.cpp	Thu May 09 17:03:44 2013 +0300
+++ b/src/ldtypes.cpp	Fri May 10 17:39:56 2013 +0300
@@ -86,7 +86,7 @@
 	str val = fmt ("2 %d", color);
 	
 	for (ushort i = 0; i < 2; ++i)
-		val.appendformat (" %s", coords[i].stringRep (false).chars ());
+		val += fmt  (" %s", coords[i].stringRep (false).chars ());
 	
 	return val;
 }
@@ -95,7 +95,7 @@
 	str val = fmt ("3 %d", color);
 	
 	for (ushort i = 0; i < 3; ++i)
-		val.appendformat (" %s", coords[i].stringRep (false).chars ());
+		val += fmt  (" %s", coords[i].stringRep (false).chars ());
 	
 	return val;
 }
@@ -104,7 +104,7 @@
 	str val = fmt ("4 %d", color);
 	
 	for (ushort i = 0; i < 4; ++i)
-		val.appendformat (" %s", coords[i].stringRep (false).chars ());
+		val += fmt  (" %s", coords[i].stringRep (false).chars ());
 	
 	return val;
 }
@@ -114,7 +114,7 @@
 	
 	// Add the coordinates
 	for (ushort i = 0; i < 4; ++i)
-		val.appendformat (" %s", coords[i].stringRep (false).chars ());
+		val += fmt  (" %s", coords[i].stringRep (false).chars ());
 	
 	return val;
 }
@@ -386,7 +386,7 @@
 		if (objType == LDObject::Vertex && objCount != 1)
 			noun = "vertices";
 		
-		text.appendformat ("%lu %s", objCount, noun.chars ());
+		text += fmt  ("%lu %s", objCount, noun.chars ());
 		firstDetails = false;
 	}
 	
@@ -606,12 +606,12 @@
 // =============================================================================
 str LDRadial::getContents () {
 	return fmt ("0 !LDFORGE RADIAL %s %d %d %d %d %s %s",
-		str (radialTypeName()).toupper ().strip (' ').chars (),
+		str (radialTypeName()).upper ().strip (' ').c (),
 		color, segs, divs, ringNum,
 		pos.stringRep (false).chars(), transform.stringRep().chars());
 }
 
-char const* g_saRadialNameRoots[] = {
+char const* g_radialNameRoots[] = {
 	"edge",
 	"cyli",
 	"disc",
@@ -641,7 +641,7 @@
 	// Compose some general information: prefix, fraction, root, ring number
 	str prefix = (divs == 16) ? "" : fmt ("%d/", divs);
 	str frac = fmt ("%d-%d", numer, denom);
-	str root = g_saRadialNameRoots[radType];
+	str root = g_radialNameRoots[radType];
 	str num = (radType == Ring || radType == Cone) ? fmt ("%d", ringNum) : "";
 	
 	// Truncate the root if necessary (7-16rin4.dat for instance).
--- a/src/main.cpp	Thu May 09 17:03:44 2013 +0300
+++ b/src/main.cpp	Fri May 10 17:39:56 2013 +0300
@@ -39,7 +39,7 @@
 // =============================================================================
 int main (int argc, char* argv[]) {
 	// Load or create the configuration
-	if (!config::load()) {
+	if (!config::load ()) {
 		printf ("Creating configuration file...\n");
 		if (config::save ())
 			printf ("Configuration file successfully created.\n");
@@ -80,25 +80,12 @@
 	va_end (va);
 }
 
-void warnf (const char* fmtstr, ...) {
+void doDevf (const char* func, const char* fmtstr, ...) {
 	va_list va;
-	va_start (va, fmtstr);
-	g_win->logVA (LOG_Warning, fmtstr, va);
-	va_end (va);
-}
-
-void errf (const char* fmtstr, ...) {
-	va_list va;
+	
+	printf ("%s: ", func);
+	
 	va_start (va, fmtstr);
-	g_win->logVA (LOG_Error, fmtstr, va);
+	vprintf (fmtstr, va);
 	va_end (va);
-}
-
-#ifndef RELEASE
-void devf (const char* fmtstr, ...) {
-	va_list va;
-	va_start (va, fmtstr);
-	g_win->logVA (LOG_Dev, fmtstr, va);
-	va_end (va);
-}
-#endif // RELEASE
\ No newline at end of file
+}
\ No newline at end of file
--- a/src/misc.cpp	Thu May 09 17:03:44 2013 +0300
+++ b/src/misc.cpp	Fri May 10 17:39:56 2013 +0300
@@ -207,7 +207,7 @@
 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
 // =============================================================================
 StringParser::StringParser (str inText, char sep) {
-	m_tokens = inText.split (sep, true);
+	m_tokens = inText.split (sep);
 	m_pos = -1;
 }
 
--- a/src/misc.h	Thu May 09 17:03:44 2013 +0300
+++ b/src/misc.h	Fri May 10 17:39:56 2013 +0300
@@ -20,7 +20,6 @@
 #define MISC_H
 
 #include "common.h"
-#include "str.h"
 #include "config.h"
 
 #define NUM_PRIMES 500
--- a/src/str.cpp	Thu May 09 17:03:44 2013 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,502 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013 Santeri Piippo
- *  
- *  This program is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <stdarg.h>
-#include <assert.h>
-#include "str.h"
-#include "common.h"
-#include "misc.h"
-
-#define ITERATE_STRING(u) \
-	for (uint u = 0; u < strlen (m_text); u++)
-
-// ============================================================================
-// vdynformat: Try to write to a formatted string with size bytes first, if
-// that fails, double the size and keep recursing until it works.
-char* vdynformat (const char* fmtstr, va_list va, long size) {
-	char* buffer = new char[size];
-	int r = vsnprintf (buffer, size - 1, fmtstr, va);
-	if (r > (signed)(size - 1) || r < 0) {
-		delete[] buffer;
-		buffer = vdynformat (fmtstr, va, size * 2);
-	}
-	return buffer;
-}
-
-// ============================================================================
-str::str () {
-	m_text = new char[1];
-	clear();
-	m_allocated = strlen (m_text);
-}
-
-str::str (const char* c) {
-	m_text = new char[1];
-	m_text[0] = '\0';
-	m_writepos = m_allocated = 0;
-	append (c);
-}
-
-str::str (char c) {
-	m_text = new char[1];
-	m_text[0] = '\0';
-	m_writepos = m_allocated = 0;
-	append (c);
-}
-
-str::str (QString c) {
-	m_text = new char[1];
-	m_text[0] = '\0';
-	m_writepos = m_allocated = 0;
-	append (c);
-}
-
-str::~str () {
-	// delete[] text;
-}
-
-// ============================================================================
-void str::clear () {
-	delete[] m_text;
-	m_text = new char[1];
-	m_text[0] = '\0';
-	m_writepos = 0;
-	m_allocated = 0;
-}
-
-// ============================================================================
-void str::resize (uint len) {
-	uint oldlen = strlen (m_text);
-	char* oldtext = new char[oldlen];
-	strncpy (oldtext, m_text, oldlen);
-	
-	delete[] m_text;
-	m_text = new char[len+1];
-	for (uint u = 0; u < len+1; u++)
-		m_text[u] = 0;
-	strncpy (m_text, oldtext, len);
-	delete[] oldtext;
-	
-	m_allocated = len;
-}
-
-// ============================================================================
-void str::dump () {
-	for (uint u = 0; u <= m_allocated; u++)
-		printf ("\t%u. %u (%c)\n", u, m_text[u], m_text[u]);
-}
-
-// ============================================================================
-// Adds a new character at the end of the string.
-void str::append (const char c) {
-	// Out of space, thus resize
-	if (m_writepos == m_allocated)
-		resize (m_allocated + 1);
-	m_text[m_writepos] = c;
-	m_writepos++;
-}
-
-void str::append (const char* c) {
-	resize (m_allocated + strlen (c));
-	
-	for (uint u = 0; u < strlen (c); u++) {
-		if (c[u] != 0)
-			append (c[u]);
-	}
-}
-
-void str::append (str c) {
-	append (c.chars());
-}
-
-void str::append (QString c) {
-	append (c.toUtf8 ().constData ());
-}
-
-// ============================================================================
-void str::appendformat (const char* c, ...) {
-	va_list v;
-	
-	va_start (v, c);
-	char* buf = vdynformat (c, v, 256);
-	va_end (v);
-	
-	append (buf);
-	delete[] buf;
-}
-
-void str::format (const char* fmt, ...) {
-	clear ();
-	
-	va_list v;
-	
-	va_start (v, fmt);
-	char* buf = vdynformat (fmt, v, 256);
-	va_end (v);
-	
-	append (buf);
-	delete[] buf;
-}
-
-// ============================================================================
-char* str::chars () {
-	return m_text;
-}
-
-// ============================================================================
-int str::first (const char* c, uint a) {
-	uint r = 0;
-	uint index = 0;
-	for (; a < m_allocated; a++) {
-		if (m_text[a] == c[r]) {
-			if (r == 0)
-				index = a;
-			
-			r++;
-			if (r == strlen (c))
-				return index;
-		} else {
-			if (r != 0) {
-				// If the string sequence broke at this point, we need to
-				// check this character again, for a new sequence just
-				// might start right here.
-				a--;
-			}
-			
-			r = 0;
-		}
-	}
-	
-	return -1;
-}
-
-// ============================================================================
-int str::last (const char* c, int a) {
-	if (a == -1)
-		a = len();
-	
-	int max = strlen (c)-1;
-	
-	int r = max;
-	for (; a >= 0; a--) {
-		if (m_text[a] == c[r]) {
-			r--;
-			if (r == -1)
-				return a;
-		} else {
-			if (r != max)
-				a++;
-			
-			r = max;
-		}
-	}
-	
-	return -1;
-}
-
-// ============================================================================
-str str::substr (uint a, uint b) {
-	if (a > len()) a = len();
-	if (b > len()) b = len();
-	
-	if (b == a)
-		return "";
-	
-	if (b < a) {
-		printf ("str::substring:: indices %u and %u given, should be the other way around, swapping..\n", a, b);
-		
-		// Swap the variables
-		uint c = a;
-		a = b;
-		b = c;
-	}
-	
-	char* s = new char[b - a + 1];
-	strncpy (s, m_text + a, b - a);
-	s[b - a] = '\0';
-	
-	str other = s;
-	delete[] s;
-	return other;
-}
-
-// ============================================================================
-void str::remove (uint idx, uint dellen) {
-	str s1 = substr (0, idx);
-	str s2 = substr (idx + dellen, -1);
-	
-	clear();
-	
-	append (s1);
-	append (s2);
-}
-
-// ============================================================================
-str str::trim (int dellen) {
-	if (dellen > 0)
-		return substr (0, len() - dellen);
-	return substr (-dellen, len());
-}
-
-// ============================================================================
-void str::replace (const char* o, const char* n, uint a) {
-	for (int idx; (idx = first (o, a)) != -1;) {
-		str s1 = substr (0, idx);
-		str s2 = substr (idx + strlen (o), len());
-		
-		clear();
-		
-		append (s1);
-		append (n);
-		append (s2);
-	}
-}
-
-// ============================================================================
-str str::strip (char c) {
-	return strip ({c});
-}
-
-str str::strip (std::initializer_list<char> unwanted) {
-	str cache = m_text;
-	uint oldlen = len();
-	
-	char* buf = new char[oldlen];
-	char* bufptr = buf;
-	for (uint i = 0; i < oldlen; i++) {
-		bool valid = true;
-		for (const char* j = unwanted.begin(); j < unwanted.end() && valid; j++)
-			if (m_text[i] == *j)
-				valid = false;
-		
-		if (valid)
-			*bufptr++ = m_text[i];
-	}
-	
-	*bufptr = '\0';
-	assert (bufptr <= buf + oldlen);
-	
-	str zResult = buf;
-	delete[] buf;
-	
-	return zResult;
-}
-
-void str::insert (char* c, uint pos) {
-	str s1 = substr (0, pos);
-	str s2 = substr (pos, len());
-	
-	clear();
-	append (s1);
-	append (c);
-	append (s2);
-}
-
-str str::reverse () {
-	char* buf = new char[len() + 1];
-	
-	for (uint i = 0; i < len(); i++)
-		buf[i] = m_text[len() - i - 1];
-	buf[len()] = '\0';
-	
-	str other = buf;
-	delete[] buf;
-	return other;
-}
-
-str str::repeat (int n) {
-	assert (n >= 0);
-	
-	str other;
-	for (int i = 0; i < n; i++)
-		other += m_text;
-	return other;
-}
-
-// ============================================================================
-bool str::isnumber () {
-	ITERATE_STRING (u) {
-		// Minus sign as the first character is allowed for negatives
-		if (!u && m_text[u] == '-')
-			continue;
-		
-		if (m_text[u] < '0' || m_text[u] > '9')
-			return false;
-	}
-	return true;
-}
-
-// ============================================================================
-bool str::isword () {
-	ITERATE_STRING (u) {
-		// lowercase letters
-		if (m_text[u] >= 'a' || m_text[u] <= 'z')
-			continue;
-		
-		// uppercase letters
-		if (m_text[u] >= 'A' || m_text[u] <= 'Z')
-			continue;
-		
-		return false;
-	}
-	return true;
-}
-
-int str::instanceof (const char* c, uint n) {
-	uint r = 0;
-	uint index = 0;
-	uint x = 0;
-	for (uint a = 0; a < m_allocated; a++) {
-		if (m_text[a] == c[r]) {
-			if (r == 0)
-				index = a;
-			
-			r++;
-			if (r == strlen (c)) {
-				if (x++ == n)
-					return index;
-				r = 0;
-			}
-		} else {
-			if (r != 0)
-				a--;
-			r = 0;
-		}
-	}
-	
-	return -1;
-}
-
-// ============================================================================
-int str::compare (const char* c) {
-	return strcmp (m_text, c);
-}
-
-int str::compare (str c) {
-	return compare (c.chars());
-}
-
-int str::icompare (const char* c) {
-	return icompare (str ((char*)c));
-}
-
-int str::icompare (str b) {
-	return strcmp (tolower().chars(), b.tolower().chars());
-}
-
-// ============================================================================
-str str::tolower () {
-	str n = m_text;
-	
-	for (uint u = 0; u < len(); u++) {
-		if (n[u] >= 'A' && n[u] < 'Z')
-			n.m_text[u] += ('a' - 'A');
-	}
-	
-	return n;
-}
-
-// ============================================================================
-str str::toupper () {
-	str n = m_text;
-	
-	for (uint u = 0; u < len(); u++) {
-		if (n[u] >= 'a' && n[u] < 'z')
-			n.m_text[u] -= ('a' - 'A');
-	}
-	
-	return n;
-}
-
-// ============================================================================
-uint str::count (char c) {
-	uint n = 0;
-	ITERATE_STRING (u)
-		if (m_text[u] == c)
-			n++;
-	return n;
-}
-
-uint str::count (char* c) {
-	uint r = 0;
-	uint tmp = 0;
-	ITERATE_STRING (u) {
-		if (m_text[u] == c[r]) {
-			r++;
-			if (r == strlen (c)) {
-				r = 0;
-				tmp++;
-			}
-		} else {
-			if (r != 0)
-				u--;
-			r = 0;
-		}
-	}
-	
-	return tmp;
-}
-
-// ============================================================================
-std::vector<str> str::split (str del, bool bNoBlanks) {
-	std::vector<str> res;
-	uint a = 0;
-	
-	// Find all separators and store the text left to them.
-	while (1) {
-		int b = first (del, a);
-		
-		if (b == -1)
-			break;
-		
-		if (!bNoBlanks || (b - a))
-			res.push_back (substr (a, b));
-		
-		a = b + strlen (del);
-	}
-	
-	// Add the string at the right of the last separator
-	if (!bNoBlanks || (len () - a))
-		res.push_back (substr (a, len ()));
-	return res;
-}
-
-std::vector<str> str::operator/ (str splitstring) {return split(splitstring);}
-std::vector<str> str::operator/ (char* splitstring) {return split(splitstring);}
-std::vector<str> str::operator/ (const char* splitstring) {return split(splitstring);}
-
-str& str::operator+= (vertex vrt) {
-	appendformat ("%s", vrt.stringRep (false).chars());
-	return *this;
-}
-
-str fmt (const char* fmt, ...) {
-	va_list va;
-	char* buf;
-	
-	va_start (va, fmt);
-	buf = vdynformat (fmt, va, 256);
-	va_end (va);
-	
-	str val = buf;
-	delete[] buf;
-	return val;
-}
\ No newline at end of file
--- a/src/str.h	Thu May 09 17:03:44 2013 +0300
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,140 +0,0 @@
-/*
- *  LDForge: LDraw parts authoring CAD
- *  Copyright (C) 2013 Santeri Piippo
- *  
- *  This program is free software: you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation, either version 3 of the License, or
- *  (at your option) any later version.
- *  
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *  
- *  You should have received a copy of the GNU General Public License
- *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
- */
-
-#ifndef STR_H
-#define STR_H
-
-#include <string.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <vector>
-#include <QString>
-
-char* vdynformat (const char* fmtstr, va_list va, long size);
-
-class vertex;
-
-// Dynamic string object, allocates memory when needed and
-// features a good bunch of manipulation methods
-class str {
-private:
-	char* m_text;
-	ushort m_writepos;
-	ushort m_allocated;
-	void resize (uint len);
-	
-public:
-	// ======================================================================
-	str ();
-	str (const char* c);
-	str (char c);
-	str (QString c);
-	~str ();
-	
-	void clear ();
-	size_t len () { return strlen (m_text); }
-	char* chars ();
-	void dump ();
-	void append (const char c);
-	void append (const char* c);
-	void append (str c);
-	void append (QString c);
-	void format (const char* fmt, ...);
-	void appendformat (const char* c, ...);
-	int first (const char* c, uint a = 0);
-	int last (const char* c, int a = -1);
-	str substr (uint a, uint b);
-	void replace (const char* o, const char* n, uint a = 0);
-	void remove (uint idx, uint dellen = 1);
-	str trim (int dellen);
-	void insert (char* c, uint pos);
-	str reverse ();
-	str repeat (int n);
-	bool isnumber ();
-	bool isword ();
-	str tolower ();
-	str toupper ();
-	int compare (const char* c);
-	int compare (str c);
-	int icompare (str c);
-	int icompare (const char* c);
-	uint count (char* c);
-	uint count (char s);
-	int instanceof (const char* s, uint n);
-	char subscript (uint pos) { return operator[] (pos); }
-	std::vector<str> split (str del, bool bNoBlanks = false);
-	str strip (char c);
-	str strip (std::initializer_list<char> unwanted);
-	char* begin () { return &m_text[0]; }
-	char* end () { return &m_text[len () - 1]; }
-	
-	str operator+ (str& c) { append (c); return *this; }
-	str& operator+= (char c) { append (c); return *this; }
-	str& operator+= (const char* c) { append (c); return *this; }
-	str& operator+= (const str c) { append (c); return *this; }
-	str& operator+= (const QString c) { append (c); return *this; }
-	str& operator+= (vertex vrt);
-	str operator* (const int repcount) { repeat (repcount); return *this; }
-	str operator- (const int trimcount) { return trim (trimcount); }std::vector<str> operator/ (str splitstring);
-	std::vector<str> operator/ (char* splitstring);
-	std::vector<str> operator/ (const char* splitstring);
-	int operator% (str splitstring) { return count (splitstring.chars()); }
-	int operator% (char* splitstring) { return count (splitstring); }
-	int operator% (const char* splitstring) { return count (str (splitstring).chars()); }
-	str operator+ () { return toupper (); }
-	str operator- () { return tolower (); }
-	str operator! () { return reverse (); }
-	size_t operator~ () { return len (); }
-	char& operator[] (int pos) { return m_text[pos]; }
-	operator char* () const { return m_text; }
-	operator QString () const { return m_text; }
-	operator int () const { return atoi (m_text); }
-	operator uint () const { return operator int(); }
-	
-	str& operator*= (const int repcount) {
-		str other = repeat (repcount);
-		clear ();
-		append (other);
-		return *this;
-	}
-	
-	str& operator-= (const int trimcount) {
-		str other = trim (trimcount);
-		clear ();
-		append (other);
-		return *this;
-	}
-	
-#define DEFINE_OPERATOR_TYPE(OPER, TYPE) \
-	bool operator OPER (TYPE other) {return compare(other) OPER 0;}
-#define DEFINE_OPERATOR(OPER) \
-	DEFINE_OPERATOR_TYPE (OPER, str) \
-	DEFINE_OPERATOR_TYPE (OPER, char*) \
-	DEFINE_OPERATOR_TYPE (OPER, const char*)
-	
-	DEFINE_OPERATOR (==)
-	DEFINE_OPERATOR (!=)
-	DEFINE_OPERATOR (>)
-	DEFINE_OPERATOR (<)
-	DEFINE_OPERATOR (>=)
-	DEFINE_OPERATOR (<=)
-};
-
-str fmt (const char* fmt, ...);
-
-#endif // STR_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/string.cpp	Fri May 10 17:39:56 2013 +0300
@@ -0,0 +1,163 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013 Santeri Piippo
+ *  
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "common.h"
+#include "string.h"
+
+str fmt (const char* fmtstr, ...) {
+	va_list va;
+	
+	va_start (va, fmtstr);
+	char* buf = dynafmt (fmtstr, va, 256);
+	va_end (va);
+	
+	str msg = buf;
+	delete[] buf;
+	return msg;
+}
+
+char* dynafmt (const char* fmtstr, va_list va, ulong size) {
+	char* buf = null;
+	ushort run = 0;
+	
+	do {
+		try {
+			buf = new char[size];
+		} catch (std::bad_alloc&) {
+			fprintf (stderr, "%s: allocation error on run #%u: tried to allocate %lu bytes\n", __func__, run + 1, size);
+			abort ();
+		}
+		
+		if (!vsnprintf (buf, size - 1, fmtstr, va)) {
+			delete[] buf;
+			buf = null;
+		}
+		
+		size *= 2;
+		++run;
+	} while (buf == null);
+	
+	return buf;
+}
+
+void String::trim (short n) {
+	if (n > 0)
+		for (short i = 0; i < n; ++i)
+			m_string.erase (m_string.end () - 1 - i);
+	else
+		for (short i = abs (n) - 1; i >= 0; ++i)
+			m_string.erase (m_string.begin () + i);
+}
+
+String String::strip (std::initializer_list<char> unwanted) {
+	String copy (m_string);
+	
+	for (char c : unwanted) {
+		for (long i = len (); i >= 0; --i)
+			if (copy[(size_t) i] == c)
+				copy.erase (i);
+	}
+	
+	return copy;
+}
+
+String String::upper() const {
+	String newstr = m_string;
+	
+	for (char& c : newstr)
+		if (c >= 'a' && c <= 'z')
+			c -= 'a' - 'A';
+	
+	return newstr;
+}
+
+String String::lower () const {
+	String newstr = m_string;
+
+	for (char& c : newstr)
+		if (c >= 'A' && c <= 'Z')
+			c += 'a' - 'A';
+	
+	return newstr;
+}
+
+vector<String> String::split (char del) const {
+	String delimstr;
+	delimstr += del;
+	return split (delimstr);
+}
+
+vector<String> String::split (String del) const {
+	std::vector<String> res;
+	size_t a = 0;
+	
+	// Find all separators and store the text left to them.
+	while (1) {
+		size_t b = first (del, a);
+		
+		if (b == npos)
+			break;
+		
+		String sub = substr (a, b);
+		if (~sub > 0)
+			res.push_back (substr (a, b));
+		
+		a = b + strlen (del);
+	}
+	
+	// Add the string at the right of the last separator
+	if (a < len ())
+		res.push_back (substr (a, len()));
+	
+	return res;
+}
+
+void String::replace (const char* a, const char* b) {
+	size_t pos;
+	
+	while ((pos = first (a)) != npos)
+		m_string = m_string.replace (pos, strlen (a), b);
+}
+
+void String::format (const char* fmtstr, ...) {
+	va_list va;
+	
+	va_start (va, fmtstr);
+	char* buf = dynafmt (fmtstr, va, 256);
+	va_end (va);
+	
+	m_string = buf;
+	delete[] buf;
+}
+
+ushort String::count (const char needle) const {
+	ushort numNeedles = 0;
+	
+	for (const char& c : m_string)
+		if (c == needle)
+			numNeedles++;
+	
+	return numNeedles;
+}
+
+String String::substr (long a, long b) const {
+	if (b == -1)
+		b = len ();
+	
+	return m_string.substr (a, b - a);
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/string.h	Fri May 10 17:39:56 2013 +0300
@@ -0,0 +1,114 @@
+/*
+ *  LDForge: LDraw parts authoring CAD
+ *  Copyright (C) 2013 Santeri Piippo
+ *  
+ *  This program is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *  
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *  
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef STR_H
+#define STR_H
+
+#include <string>
+#include <stdarg.h>
+#include <QString>
+
+using std::vector;
+
+// =========================================================================================================================================
+char* dynafmt (const char* fmtstr, va_list va, ulong size);
+
+// =========================================================================================================================================
+typedef class String {
+public:
+#define STR_COMPARE_OPERATOR(T, OP) (T other) const { return compare (other) OP 0; }
+	
+	typedef typename std::string::iterator it;
+	typedef typename std::string::const_iterator c_it;
+	typedef vector<String> stringlist;
+	
+	String () {}
+	String	(const char* data) { m_string = data; }
+	String	(const QString data) { m_string = data.toStdString (); }
+	String (std::string data) { m_string = data; }
+	
+	void		append			(const char* data) { m_string.append (data); }
+	void		append			(const char data) { m_string.push_back (data); }
+	void		append			(const String data) { m_string.append (data.chars ()); }
+	it			begin			() { return m_string.begin (); }
+	const char*	c				() const { return chars (); }
+	size_t		capacity		() const { return m_string.capacity (); }
+	const char*	chars			() const { return m_string.c_str (); }
+	int			compare			(const char* other) const { return m_string.compare (other); }
+	int			compare			(String other) const { return m_string.compare (other); }
+	it			end				() { return m_string.end (); }
+	c_it		cbegin			() const { return m_string.cbegin (); }
+	c_it		cend			() const { return m_string.end (); }
+	void		clear			() { m_string.clear (); }
+	ushort		count			(const char needle) const;
+	bool		empty			() const { return m_string.empty (); }
+	void		erase			(size_t pos) { m_string.erase (m_string.begin () + pos); }
+	size_t		first			(const char* other, size_t pos = 0) const { return m_string.find_first_of (other, pos); }
+	size_t		first			(const char other, size_t pos = 0) const { return m_string.find_first_of (other, pos); }
+	size_t		first			(const String other, size_t pos = 0) const { return m_string.find_first_of (other, pos); }
+	void		format			(const char* fmtstr, ...);
+	void		insert			(size_t pos, char c) { m_string.insert (m_string.begin () + pos, c); }
+	size_t		last			(const char* other, size_t pos = 0) const { return m_string.find_last_of (other, pos); }
+	size_t		last			(const char other, size_t pos = 0) const { return m_string.find_last_of (other, pos); }
+	size_t		last			(const String other, size_t pos = 0) const { return m_string.find_last_of (other, pos); }
+	size_t		len				() const { return m_string.length (); }
+	String		lower			() const;
+	size_t		maxSize			() const { return m_string.max_size (); }
+	void		replace			(const char* a, const char* b);
+	void		resize			(size_t n) { m_string.resize (n); }
+	void		shrinkToFit		() { m_string.shrink_to_fit (); }
+	stringlist	split			(String del) const;
+	stringlist	split			(char del) const;
+	String		strip			(char unwanted) { return strip ({unwanted}); }
+	String		strip			(std::initializer_list<char> unwanted);
+	String		substr			(long a, long b) const;
+	void		trim			(short n);
+	String		upper			() const;
+	void		writeToFile		(FILE* fp) const { fwrite (chars (), 1, len (), fp); }
+	
+	String		operator+		(const String data) const { String newstr = *this; newstr += data; return newstr; }
+	String		operator+		(const char* data) const { String newstr = *this; newstr += data; return newstr; }
+	String&		operator+=		(const String data) { append (data); return *this; }
+	String&		operator+=		(const char* data) { append (data); return *this; }
+	String&		operator+=		(const char data) { append (data); return *this; }
+	String		operator+		() const { return upper (); }
+	String		operator-		() const { return lower (); }
+	String		operator-		(short n) const { String newstr = m_string; newstr -= n; return newstr; }
+	String&		operator-=		(short n) { trim (n); return *this; }
+	size_t		operator~		() const { return len (); }
+	vector<String> operator/	(String del) const { return split (del); }
+	char&		operator[]		(size_t n) { return m_string[n]; }
+	const char&	operator[]		(size_t n) const { return m_string[n]; }
+	bool		operator==		STR_COMPARE_OPERATOR (const char*, ==)
+	bool		operator==		STR_COMPARE_OPERATOR (String, ==)
+	bool		operator!=		STR_COMPARE_OPERATOR (const char*, !=)
+	bool		operator!=		STR_COMPARE_OPERATOR (String,  !=)
+	bool		operator!		() const { return empty (); }
+	operator const char*		() const { return chars (); }
+	operator QString			() { return chars (); }
+	
+private:
+	std::string m_string;
+} str;
+
+static const std::size_t npos = std::string::npos;
+
+// =========================================================================================================================================
+str fmt (const char* fmtstr, ...);
+
+#endif // STR_H
\ No newline at end of file
--- a/src/types.h	Thu May 09 17:03:44 2013 +0300
+++ b/src/types.h	Fri May 10 17:39:56 2013 +0300
@@ -126,7 +126,7 @@
 			if (i > 0)
 				val += ' ';
 			
-			val.appendformat ("%s", ftoa (m_vals[i]).chars());
+			val += fmt ("%s", ftoa (m_vals[i]).chars());
 		}
 		
 		return val;	

mercurial