diff --git a/src/describescreen.cpp b/src/describescreen.cpp
index 19c52d15..4a7afca5 100644
--- a/src/describescreen.cpp
+++ b/src/describescreen.cpp
@@ -14,7 +14,7 @@ void TextWindow::ScreenEditTtfText(int link, uint32_t v) {
hRequest hr = { v };
Request *r = SK.GetRequest(hr);
- SS.TW.ShowEditControl(10, r->str.c_str());
+ SS.TW.ShowEditControl(10, r->str);
SS.TW.edit.meaning = EDIT_TTF_TEXT;
SS.TW.edit.request = hr;
}
diff --git a/src/drawconstraint.cpp b/src/drawconstraint.cpp
index af22ccb7..b61a0cc5 100644
--- a/src/drawconstraint.cpp
+++ b/src/drawconstraint.cpp
@@ -124,7 +124,7 @@ void Constraint::DoLabel(Vector ref, Vector *labelPos, Vector gr, Vector gu) {
if(dogd.drawing) {
- ssglWriteTextRefCenter(s.c_str(), th, ref, gr, gu, LineCallback, this);
+ ssglWriteTextRefCenter(s, th, ref, gr, gu, LineCallback, this);
} else {
double l = swidth/2 - sheight/2;
l = max(l, 5/SS.GW.scale);
diff --git a/src/drawentity.cpp b/src/drawentity.cpp
index 75eb3f6c..28647e41 100644
--- a/src/drawentity.cpp
+++ b/src/drawentity.cpp
@@ -447,7 +447,7 @@ void Entity::GenerateBezierCurves(SBezierList *sbl) {
Vector v = topLeft.Minus(botLeft);
Vector u = (v.Cross(n)).WithMagnitude(v.Magnitude());
- SS.fonts.PlotString(font.c_str(), str.c_str(), sbl, botLeft, u, v);
+ SS.fonts.PlotString(font, str, sbl, botLeft, u, v);
break;
}
@@ -610,7 +610,7 @@ void Entity::DrawOrGetDistance(void) {
std::string str = DescriptionString().substr(5);
double th = DEFAULT_TEXT_HEIGHT;
if(dogd.drawing) {
- ssglWriteText(str.c_str(), th, mm2, u, v, NULL, NULL);
+ ssglWriteText(str, th, mm2, u, v, NULL, NULL);
} else {
Vector pos = mm2.Plus(u.ScaledBy(ssglStrWidth(str, th)/2)).Plus(
v.ScaledBy(ssglStrHeight(th)/2));
diff --git a/src/generate.cpp b/src/generate.cpp
index 18a84cab..d34a83bb 100644
--- a/src/generate.cpp
+++ b/src/generate.cpp
@@ -242,7 +242,7 @@ void SolveSpaceUI::GenerateAll(int first, int last, bool andFindFree, bool genFo
glPushMatrix();
glTranslated(left+8, top-20, 0);
glScaled(1, -1, 1);
- ssglBitmapText(msg.c_str(), Vector::From(0, 0, 0));
+ ssglBitmapText(msg, Vector::From(0, 0, 0));
glPopMatrix();
glFlush();
glDrawBuffer(GL_BACK);
diff --git a/src/glhelper.cpp b/src/glhelper.cpp
index e9ed14c9..377e1030 100644
--- a/src/glhelper.cpp
+++ b/src/glhelper.cpp
@@ -40,11 +40,7 @@ static const VectorGlyph &GetVectorGlyph(char32_t chr) {
double ssglStrWidth(const std::string &str, double h)
{
int width = 0;
- const char *iter = str.c_str();
- while(*iter) {
- char32_t chr;
- iter = ReadUTF8(iter, &chr);
-
+ for(char32_t chr : ReadUTF8(str)) {
const VectorGlyph &glyph = GetVectorGlyph(chr);
if(glyph.baseCharacter != 0) {
const VectorGlyph &baseGlyph = GetVectorGlyph(glyph.baseCharacter);
@@ -149,11 +145,7 @@ void ssglWriteText(const std::string &str, double h, Vector t, Vector u, Vector
double scale = FONT_SCALE(h) / SS.GW.scale;
Vector o = { 5.0, 5.0 };
- const char *iter = str.c_str();
- while(*iter) {
- char32_t chr;
- iter = ReadUTF8(iter, &chr);
-
+ for(char32_t chr : ReadUTF8(str)) {
const VectorGlyph &glyph = GetVectorGlyph(chr);
o.x += ssglDrawCharacter(glyph, t, o, u, v, scale, fn, fndata);
}
@@ -678,14 +670,11 @@ void ssglBitmapCharQuad(char32_t chr, double x, double y)
}
}
-void ssglBitmapText(const char *str, Vector p)
+void ssglBitmapText(const std::string &str, Vector p)
{
glEnable(GL_TEXTURE_2D);
glBegin(GL_QUADS);
- while(*str) {
- char32_t chr;
- str = ReadUTF8(str, &chr);
-
+ for(char32_t chr : ReadUTF8(str)) {
ssglBitmapCharQuad(chr, p.x, p.y);
p.x += 8 * ssglBitmapCharWidth(chr);
}
diff --git a/src/solvespace.cpp b/src/solvespace.cpp
index e4b646cb..4161d533 100644
--- a/src/solvespace.cpp
+++ b/src/solvespace.cpp
@@ -399,7 +399,7 @@ bool SolveSpaceUI::Autosave()
void SolveSpaceUI::RemoveAutosave()
{
std::string autosaveFile = saveFile + AUTOSAVE_SUFFIX;
- ssremove(autosaveFile.c_str());
+ ssremove(autosaveFile);
}
bool SolveSpaceUI::OkayToStartNewFile(void) {
diff --git a/src/solvespace.h b/src/solvespace.h
index ae6b216e..64935159 100644
--- a/src/solvespace.h
+++ b/src/solvespace.h
@@ -310,6 +310,25 @@ typedef IdList ParamList;
// Utility functions that are provided in the platform-independent code.
+class utf8_iterator : std::iterator {
+ const char *p, *n;
+public:
+ utf8_iterator(const char *p) : p(p), n(NULL) {}
+ bool operator==(const utf8_iterator &i) const { return p==i.p; }
+ bool operator!=(const utf8_iterator &i) const { return p!=i.p; }
+ ptrdiff_t operator- (const utf8_iterator &i) const { return p -i.p; }
+ utf8_iterator& operator++() { **this; p=n; n=NULL; return *this; }
+ utf8_iterator operator++(int) { utf8_iterator t(*this); operator++(); return t; }
+ char32_t operator*();
+};
+class ReadUTF8 {
+ const std::string &str;
+public:
+ ReadUTF8(const std::string &str) : str(str) {}
+ utf8_iterator begin() const { return utf8_iterator(&str[0]); }
+ utf8_iterator end() const { return utf8_iterator(&str[str.length()]); }
+};
+
void ssglLineWidth(GLfloat width);
void ssglVertex3v(Vector u);
void ssglAxisAlignedQuad(double l, double r, double t, double b, bool lone = true);
@@ -345,7 +364,7 @@ void ssglDepthRangeOffset(int units);
void ssglDepthRangeLockToFront(bool yes);
void ssglDrawPixelsWithTexture(uint8_t *data, int w, int h);
void ssglInitializeBitmapFont();
-void ssglBitmapText(const char *str, Vector p);
+void ssglBitmapText(const std::string &str, Vector p);
void ssglBitmapCharQuad(char32_t chr, double x, double y);
int ssglBitmapCharWidth(char32_t chr);
#define TEXTURE_BACKGROUND_IMG 10
@@ -362,8 +381,6 @@ void MakeMatrix(double *mat, double a11, double a12, double a13, double a14,
double a31, double a32, double a33, double a34,
double a41, double a42, double a43, double a44);
bool MakeAcceleratorLabel(int accel, char *out);
-const char *ReadUTF8(const char *str, char32_t *chr);
-bool StringAllPrintable(const char *str);
bool FilenameHasExtension(const std::string &str, const char *ext);
void Message(const char *str, ...);
void Error(const char *str, ...);
diff --git a/src/style.cpp b/src/style.cpp
index 76cf353b..a14a9216 100644
--- a/src/style.cpp
+++ b/src/style.cpp
@@ -476,7 +476,7 @@ void TextWindow::ShowListOfStyles(void) {
void TextWindow::ScreenChangeStyleName(int link, uint32_t v) {
hStyle hs = { v };
Style *s = Style::Get(hs);
- SS.TW.ShowEditControl(12, s->name.c_str());
+ SS.TW.ShowEditControl(12, s->name);
SS.TW.edit.style = hs;
SS.TW.edit.meaning = EDIT_STYLE_NAME;
}
diff --git a/src/textwin.cpp b/src/textwin.cpp
index 2aa81141..f5d6b513 100644
--- a/src/textwin.cpp
+++ b/src/textwin.cpp
@@ -248,20 +248,15 @@ void TextWindow::Printf(bool halfLine, const char *fmt, ...) {
break;
}
} else {
- char32_t chr;
- const char *fmtNext = ReadUTF8(fmt, &chr);
- strncpy(buf, fmt, fmtNext - fmt);
- buf[fmtNext - fmt] = '\0';
+ utf8_iterator it2(fmt), it1 = it2++;
+ strncpy(buf, fmt, it2 - it1);
+ buf[it2 - it1] = '\0';
}
- const char *bufIter = buf;
- while(*bufIter) {
- char32_t chr;
- bufIter = ReadUTF8(bufIter, &chr);
-
- for(int i = 0; i < ssglBitmapCharWidth(chr); i++) {
+ for(utf8_iterator it(buf); *it; ++it) {
+ for(int i = 0; i < ssglBitmapCharWidth(*it); i++) {
if(c >= MAX_COLS) goto done;
- text[r][c] = (i == 0) ? chr : ' ';
+ text[r][c] = (i == 0) ? *it : ' ';
meta[r][c].fg = fg;
meta[r][c].bg = bg;
meta[r][c].bgRgb = bgRgb;
@@ -463,7 +458,7 @@ void TextWindow::DrawOrHitTestIcons(int how, double mx, double my)
ssglAxisAlignedLineLoop(ox, ox+tw, oy, oy+LINE_HEIGHT);
glColor4d(0, 0, 0, 1);
- ssglBitmapText(str.c_str(), Vector::From(ox+5, oy-3+LINE_HEIGHT, 0));
+ ssglBitmapText(str, Vector::From(ox+5, oy-3+LINE_HEIGHT, 0));
} else {
if(!hoveredIcon ||
(hoveredIcon != tooltippedIcon))
diff --git a/src/toolbar.cpp b/src/toolbar.cpp
index 80e8f27f..481c35ed 100644
--- a/src/toolbar.cpp
+++ b/src/toolbar.cpp
@@ -233,7 +233,7 @@ bool GraphicsWindow::ToolbarDrawOrHitTest(int mx, int my,
glPushMatrix();
glTranslated(ox+5, oy+3, 0);
glScaled(1, -1, 1);
- ssglBitmapText(str.c_str(), Vector::From(0, 0, 0));
+ ssglBitmapText(str, Vector::From(0, 0, 0));
glPopMatrix();
}
ssglDepthRangeLockToFront(false);
diff --git a/src/ttf.cpp b/src/ttf.cpp
index 0a4fb233..4f7bb75c 100644
--- a/src/ttf.cpp
+++ b/src/ttf.cpp
@@ -213,12 +213,8 @@ static const FT_Outline_Funcs outline_funcs = {
void TtfFont::PlotString(const std::string &str,
SBezierList *sbl, Vector origin, Vector u, Vector v)
{
- const char *cstr = str.c_str();
FT_Pos dx = 0;
- while(*cstr) {
- char32_t chr;
- cstr = ReadUTF8(cstr, &chr);
-
+ for(char32_t chr : ReadUTF8(str)) {
uint32_t gid = FT_Get_Char_Index(fontFace, chr);
if (gid == 0) {
dbp("freetype: CID-to-GID mapping for CID 0x%04x failed: %s; using CID as GID",
diff --git a/src/util.cpp b/src/util.cpp
index 6909f7c0..828d717d 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -25,39 +25,26 @@ std::string SolveSpace::ssprintf(const char *fmt, ...)
return result;
}
-// See https://github.com/GNOME/glibmm/blob/2fbd9f23/glib/glibmm/ustring.cc#L227
-const char *SolveSpace::ReadUTF8(const char *str, char32_t *result)
+char32_t utf8_iterator::operator*()
{
- *result = (unsigned char) *str;
+ const uint8_t *it = (const uint8_t*) this->p;
+ char32_t result = *it;
- if((*result & 0x80) != 0)
- {
+ if((result & 0x80) != 0) {
unsigned int mask = 0x40;
- do
- {
- *result <<= 6;
- const unsigned int c = (unsigned char) (*++str);
+ do {
+ result <<= 6;
+ unsigned int c = (*++it);
mask <<= 5;
- *result += c - 0x80;
- }
- while((*result & mask) != 0);
+ result += c - 0x80;
+ } while((result & mask) != 0);
- *result &= mask - 1;
+ result &= mask - 1;
}
- return str + 1;
-}
-
-bool SolveSpace::StringAllPrintable(const char *str)
-{
- const char *t;
- for(t = str; *t; t++) {
- if(!(isalnum(*t) || *t == '-' || *t == '_')) {
- return false;
- }
- }
- return true;
+ this->n = (const char*) (it + 1);
+ return result;
}
bool SolveSpace::FilenameHasExtension(const std::string &str, const char *ext)