Fri, 10 May 2013 17:39:56 +0300
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...
--- 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