String.cpp

Go to the documentation of this file.
00001 /*
00002 
00003 $Header$
00004 
00005 */
00006 
00007 #include <cstdio>
00008 #include <cmath>
00009 #include <time.h>
00010 #include <sys/time.h>
00011 #include <stdlib.h>
00012 #include <stdio.h>
00013 
00014 #include "md5.h"
00015 
00016 #include "Error.h"
00017 #include "Parser.h"
00018 #include "Utils.h"
00019 #include "Memory.h"
00020 
00021 #include "String.h"
00022 
00023 bool String::_colorEnabled(true);
00024 
00025 // Public methods.
00026 
00027 String::String() : string()
00028 {
00029 }
00030 
00031 String::String(const char *str) : string(str)
00032 {
00033 }
00034 
00035 String::String(const string &str) : string(str)
00036 {
00037 }
00038 
00039 String::String(const char *format, va_list args) : string()
00040 {
00041   vsprintf(format, args);
00042 }
00043 
00044 String::String(const unsigned int size, const char fill) : string(size, fill)
00045 {
00046 }
00047 
00048 String::String(const char *data, unsigned int size) : string()
00049 {
00050   if (size)
00051     assign(data, size);
00052   else
00053     assign(data);
00054 }
00055 
00056 String::~String()
00057 {
00058 }
00059 
00060 String &String::sprintf(const char *format, ...)
00061 {
00062   va_list args;
00063 
00064   va_start(args, format);
00065   vsprintf(format, args);
00066   va_end(args);
00067   return *this;
00068 }
00069 
00070 String &String::vsprintf(const char *format, va_list args)
00071 {
00072   static char staticBuf[STRING_PRINTF_INIT_SIZE];
00073   bool        staticFlag = true;
00074   int         n, size = STRING_PRINTF_INIT_SIZE;
00075   char        *p = staticBuf;
00076   va_list     ap;
00077 
00078   if (!format) {
00079     ERROR(MSG_NULL_POINTER);
00080     return *this;
00081   }
00082 
00083   while (true) {
00084     // Try to print in the allocated space (first time it is static buffer)
00085     va_copy(ap, args);
00086     if ((n = ::vsnprintf(p, size, format, ap)) < 0) {
00087       va_end(ap);
00088       if (!staticFlag)
00089         MEM_FREE(p);
00090       ERROR(MSG_STRING_PRINTF, strerror(errno));
00091       return *this;
00092     }
00093     va_end(ap);
00094 
00095     // Print is OK, free buffer if necessary and return
00096     if (n < size) {
00097       assign(p);
00098       if (!staticFlag)
00099         MEM_FREE(p);
00100       return *this;
00101     }
00102 
00103     // Print is out of buffer
00104     if (staticFlag) {
00105       // First time - allocate buffer dynamically
00106       size = n + 1;
00107       if (size > (int)STRING_PRINTF_MAX_SIZE) {
00108         ERROR(MSG_STRING_TOO_BIG, size, STRING_PRINTF_MAX_SIZE);
00109         return *this;
00110       }
00111 
00112       if (!(p = (char *)MEM_ALLOC(size))) {
00113         ERROR(MSG_MEMORY_CANNOT_ALLOCATE, size, strerror(errno));
00114         return *this;
00115       }
00116       staticFlag = false;
00117     } else {
00118         // Second time - buffer should be enough
00119         ERROR(MSG_STRING_PRINTF, "Cannot allocate memory");
00120         MEM_FREE(p);
00121         return *this;
00122       }
00123   }
00124   return *this;
00125 }
00126 
00127 String &String::toLower()
00128 {
00129   string::size_type i, len = length();
00130 
00131   for (i = 0; i < len; ++i)
00132     at(i) = tolower(at(i));
00133   return *this;
00134 }
00135 
00136 String String::toLower(const String &str)
00137 {
00138   String s;
00139   string::size_type i, len = str.length();
00140 
00141   for (i = 0; i < len; ++i)
00142     s += tolower(str[i]);
00143   return s;
00144 }
00145 
00146 String &String::toUpper()
00147 {
00148   string::size_type i, len = length();
00149 
00150   for (i = 0; i < len; ++i)
00151     at(i) = toupper(at(i));
00152   return *this;
00153 }
00154 
00155 String String::toUpper(const String &str)
00156 {
00157   String s;
00158   string::size_type i, len = str.length();
00159 
00160   for (i = 0; i < len; ++i)
00161     s += toupper(str[i]);
00162   return s;
00163 }
00164 
00165 String &String::md5()
00166 {
00167   assign(md5(*this));
00168   return *this;
00169 }
00170 
00171 String String::md5(const String &str)
00172 {
00173   md5_state_t state;
00174   md5_byte_t digest[16];
00175   char hexOutput[33];
00176   unsigned int i;
00177 
00178   md5_init(&state);
00179   md5_append(&state, (const md5_byte_t *)str.c_str(), str.length());
00180   md5_finish(&state, digest);
00181   for (i = 0; i < 16; ++i)
00182     ::sprintf(hexOutput + (i << 1), "%02X", digest[i]);
00183   return hexOutput;
00184 }
00185 
00186 String &String::setNum(const int n, const NumberBase base)
00187 {
00188   assign(number(n, base));
00189   return *this;
00190 }
00191 
00192 String &String::setNum(const unsigned int n, NumberBase base)
00193 {
00194   assign(number(n, base));
00195   return *this;
00196 }
00197 
00198 String &String::setNum(const long long n, const NumberBase base)
00199 {
00200   assign(number(n, base));
00201   return *this;
00202 }
00203 
00204 String &String::setNum(const unsigned long long n, const NumberBase base)
00205 {
00206   assign(number(n, base));
00207   return *this;
00208 }
00209 
00210 String &String::setNum(const double n)
00211 {
00212   assign(number(n));
00213   return *this;
00214 }
00215 
00216 String &String::setBool(const bool b)
00217 {
00218   assign(boolean(b));
00219   return *this;
00220 }
00221 
00222 bool String::isTrue() const
00223 {
00224   return isTrue(*this);
00225 }
00226 
00227 int String::toInt(int &n) const
00228 {
00229   char *err;
00230 
00231   n = (int)strtol(c_str(), &err, 0);
00232   if (*err)
00233     return ERROR(MSG_STRING_CANNOT_CONVERT, c_str(), "int", err);
00234 
00235   return OK;
00236 }
00237 
00238 int String::toUint(unsigned int &n) const
00239 {
00240   char *err;
00241 
00242   n = strtoul(c_str(), &err, 0);
00243   if (*err)
00244     return ERROR(MSG_STRING_CANNOT_CONVERT, c_str(), "unsigned int", err);
00245 
00246   return OK;
00247 }
00248 
00249 int String::toLongLong(long long &n) const
00250 {
00251   char *err;
00252 
00253   n = strtoll(c_str(), &err, 0);
00254   if (*err)
00255     return ERROR(MSG_STRING_CANNOT_CONVERT, c_str(), "long long", err);
00256 
00257   return OK;
00258 }
00259 
00260 int String::toDouble(double &n) const
00261 {
00262   char *err;
00263 
00264   n = strtod(c_str(), &err);
00265   if (*err)
00266     return ERROR(MSG_STRING_CANNOT_CONVERT, c_str(), "double", err);
00267 
00268   return OK;
00269 }
00270 
00271 String &String::trim(const bool asciiOnly)
00272 {
00273   string::size_type i, j, len = length();
00274 
00275   for (i = 0; i < len; i++) {
00276     if (at(i) > ' ')
00277       if (asciiOnly) {
00278         if (at(i) < 127)
00279           break;
00280       } else
00281           break;
00282   }
00283   for (j = len - 1; j != 0; j--) {
00284     if (at(j) > ' ')
00285       if (asciiOnly) {
00286         if (at(j) < 127)
00287           break;
00288       } else
00289           break;
00290   }
00291   assign(substr(i, j - i + 1));
00292   return *this;
00293 }
00294 
00295 String &String::replaceCtrlChars(const char replacement)
00296 {
00297   unsigned int i, len = length();
00298 
00299   for (i = 0; i < len; ++i)
00300     if (!isprint(at(i)))
00301       at(i) = replacement;
00302 
00303   return *this;
00304 }
00305 
00306 String &String::replaceChar(const char oldChar, const char newChar)
00307 {
00308   unsigned int i, len = length();
00309 
00310   for (i = 0; i < len; ++i)
00311     if (at(i) == oldChar)
00312       at(i) = newChar;
00313 
00314   return *this;
00315 }
00316 
00317 String &String::replaceSubStr(const string &oldStr, const string &newStr)
00318 {
00319   unsigned int i = 0;
00320   unsigned int oldLen = oldStr.length();
00321   unsigned int newLen = newStr.length();
00322   while ((i = find(oldStr, i)) != npos) {
00323     replace(i, oldLen, newStr);
00324     i += newLen;
00325   }
00326   return *this;
00327 }
00328 
00329 String &String::align(const unsigned int width, const Alignment al)
00330 {
00331   StringList pars;
00332   StringList words;
00333   unsigned int parNum, wordNum, begin, end, lineWidth, wordWidth;
00334   unsigned int spaceNum, spaceRem;
00335   unsigned int i, j, k;
00336   String text;
00337   String space;
00338   int res;
00339 
00340   if (FAILED(res = Parser::split(*this, pars, 0, "\r\n", false))) {
00341     ERROR_BACKTRACE(res);
00342     return *this;
00343   }
00344   parNum = pars.size();
00345   for (k = 0; k < parNum; ++k) {
00346     if (k > 0)
00347       text.append(String::eol());
00348     if (FAILED(res = Parser::split(pars[k], words, 0, " \t"))) {
00349       ERROR_BACKTRACE(res);
00350       return *this;
00351     }
00352     wordNum = words.size();
00353     begin = end = 0;
00354     lineWidth = 0;
00355     for (i = 0; i < wordNum; ++i) {
00356       wordWidth = words[i].colorLength();
00357       if (lineWidth + end - begin + wordWidth + 1 <= width) {
00358         lineWidth += wordWidth;
00359         end = i;
00360       } else {
00361           spaceNum = al == ALIGN_JUSTIFY ? (width - lineWidth) / (end - begin) : 1;
00362           spaceRem = al == ALIGN_JUSTIFY ? (width - lineWidth) % (end - begin) : 0;
00363           if (begin != 0)
00364             text.append(String::eol());
00365           if (al == ALIGN_RIGHT) {
00366             space.assign(width - lineWidth - (end - begin), ' ');
00367             text.append(space);
00368           } else
00369               if (al == ALIGN_CENTER) {
00370                 space.assign((width - lineWidth - (end - begin)) >> 1, ' ');
00371                 text.append(space);
00372               }
00373           for (j = begin; j <= end; ++j) {
00374             text.append(words[j]);
00375             if (j < end - 1) {
00376               if (spaceRem != 0) {
00377                 space.assign(spaceNum + 1, ' ');
00378                 --spaceRem;
00379               } else
00380                   space.assign(spaceNum, ' ');
00381               text.append(space);
00382             } else
00383                 if (j == end - 1) {
00384                   space.assign(spaceNum + spaceRem, ' ');
00385                   text.append(space);
00386                 }
00387           }
00388           begin = end = i;
00389           lineWidth = wordWidth;
00390         }
00391     }
00392 
00393     if (lineWidth != 0) {
00394       if (begin != 0)
00395         text.append(String::eol());
00396       if (al == ALIGN_CENTER) {
00397         space.assign((width - lineWidth - (end - begin)) >> 1, ' ');
00398         text.append(space);
00399       }
00400       for (j = begin; j <= end; ++j) {
00401         text.append(words[j]);
00402         if (j <= end - 1)
00403           text.append(" ");
00404       }
00405     }
00406   }
00407   assign(text);
00408   return *this;
00409 }
00410 
00411 bool String::contains(const String &str, const bool ignoreCase) const
00412 {
00413   return ignoreCase ? strcasestr(c_str(), CSTRING(str)) != NULL : strstr(c_str(), CSTRING(str)) != NULL;
00414 }
00415 
00416 String &String::intersection(const String &str, const bool ignoreCase)
00417 {
00418   if (empty())
00419     assign(str);
00420   else {
00421     unsigned int i, len = MIN(str.length(), length());
00422 
00423     for (i = 0; i < len; ++i)
00424       if (ignoreCase) {
00425         if (tolower(at(i)) != tolower(str[i]))
00426           break;
00427       } else
00428           if (at(i) != str[i])
00429             break;
00430     resize(i);
00431   }
00432 
00433   return *this;
00434 }
00435 
00436 bool String::equals(const String &str, const bool ignoreCase) const
00437 {
00438   unsigned int i, len;
00439 
00440   if ((len = length()) != str.length())
00441     return false;
00442 
00443   if (ignoreCase) {
00444     for (i = 0; i < len; ++i)
00445       if (tolower(at(i)) != tolower(str[i]))
00446         return false;
00447   } else
00448       for (i = 0; i < len; ++i)
00449         if (at(i) != str[i])
00450           return false;
00451   return true;
00452 }
00453 
00454 // Color stuff.
00455 
00456 String &String::colorize(const String &fgColor, const String &bgColor)
00457 {
00458   assign(colorize(*this, fgColor, bgColor));
00459   return *this;
00460 }
00461 
00462 String &String::parseXml()
00463 {
00464   assign(parseXml(*this));
00465   return *this;
00466 }
00467 
00468 unsigned int String::colorLength() const
00469 {
00470   unsigned int len = 0;
00471   bool escSeq = false;
00472   const char *p;
00473 
00474   for (p = c_str(); *p; ++p)
00475     if (escSeq && *p == 'm')
00476       escSeq = false;
00477     else
00478       if (*p == '\033')
00479         escSeq = true;
00480       else
00481         if (!escSeq)
00482           ++len;
00483 
00484   return len;
00485 }
00486 
00487 const char *String::eol()
00488 {
00489   return "\r\n";
00490 }
00491 
00492 String String::number(const int n, const NumberBase base)
00493 {
00494   char s[64];
00495 
00496   switch (base) {
00497     case BASE_HEX:
00498       ::sprintf(s, "%x", n);
00499       break;
00500     case BASE_OCT:
00501       ::sprintf(s, "%o", n);
00502       break;
00503     default:
00504       ::sprintf(s, "%d", n);
00505       break;
00506   }
00507   return s;
00508 }
00509 
00510 String String::number(const unsigned int n, const NumberBase base)
00511 {
00512   char s[64];
00513 
00514   switch (base) {
00515     case BASE_HEX:
00516       ::sprintf(s, "%x", n);
00517       break;
00518     case BASE_OCT:
00519       ::sprintf(s, "%o", n);
00520       break;
00521     default:
00522       ::sprintf(s, "%u", n);
00523       break;
00524   }
00525   return s;
00526 }
00527 
00528 String String::number(const long long n, const NumberBase base)
00529 {
00530   char s[128];
00531 
00532   switch (base) {
00533     case BASE_HEX:
00534       ::sprintf(s, "%llx", n);
00535       break;
00536     case BASE_OCT:
00537       ::sprintf(s, "%llo", n);
00538       break;
00539     default:
00540       ::sprintf(s, "%lld", n);
00541       break;
00542   }
00543   return s;
00544 }
00545 
00546 String String::number(const unsigned long long n, const NumberBase base)
00547 {
00548   char s[128];
00549 
00550   switch (base) {
00551     case BASE_HEX:
00552       ::sprintf(s, "%llx", n);
00553       break;
00554     case BASE_OCT:
00555       ::sprintf(s, "%llo", n);
00556       break;
00557     default:
00558       ::sprintf(s, "%llu", n);
00559       break;
00560   }
00561   return s;
00562 }
00563 
00564 String String::number(const double n)
00565 {
00566   char s[64];
00567 
00568   ::sprintf(s, "%f", n);
00569   return s;
00570 }
00571 
00572 String String::boolean(const bool b)
00573 {
00574   return b ? "true" : "false";
00575 }
00576 
00577 bool String::isTrue(const String &str)
00578 {
00579   String yes(str);
00580 
00581   yes.toLower();
00582   return yes == "y" || yes == "1" || yes == "yes" || yes == "true" || yes == "on";
00583 }
00584 
00585 String String::timestamp()
00586 {
00587   struct timeval tm;
00588   struct timezone tz;
00589   struct tm *time;
00590   char ts[64];
00591 
00592   gettimeofday(&tm, &tz);
00593   time = localtime(&(tm.tv_sec));
00594   snprintf(ts, sizeof(ts), "%02u:%02u:%02u:%06lu", time->tm_hour, time->tm_min, time->tm_sec, tm.tv_usec);
00595 
00596   return ts;
00597 }
00598 
00599 // Color stuff.
00600 
00601 String String::colorize(const String &str, const String &fgColor, const String &bgColor)
00602 {
00603   return _colorEnabled ? String(CONSOLE_COLOR_ECHO_ESCAPE + fgColor + bgColor + str + CONSOLE_COLOR_REGULAR) : str;
00604 }
00605 
00606 int String::setColorEnabled(const bool yes)
00607 {
00608   _colorEnabled = yes;
00609   return OK;
00610 }
00611 
00612 String String::parseXml(const String &xmlStr)
00613 {
00614   String coloredStr = xmlStr;
00615   unsigned int i = 0;
00616   unsigned int len;
00617   unsigned int p;
00618 
00619   while (!STRING_COLOR_TAGS[i].name.empty()) {
00620     len = STRING_COLOR_TAGS[i].name.length();
00621     while ((p = coloredStr.find("<" + STRING_COLOR_TAGS[i].name + ">")) != npos) {
00622       coloredStr.replace(p, len + 2, _colorEnabled ? CONSOLE_COLOR_ECHO_ESCAPE + STRING_COLOR_TAGS[i].color : "");
00623       if ((p = coloredStr.find("</" + STRING_COLOR_TAGS[i].name + ">")) != npos)
00624         coloredStr.replace(p, len + 3, _colorEnabled ? CONSOLE_COLOR_ECHO_ESCAPE + String(CONSOLE_COLOR_REGULAR) : "");
00625       else
00626         WARNING(MSG_STRING_MALFORMED_XML, CSTRING(STRING_COLOR_TAGS[i].name));
00627     }
00628     ++i;
00629   }
00630 
00631   return coloredStr;
00632 }
00633 
00634 unsigned int String::colorLength(const char *str)
00635 {
00636   unsigned int len = 0;
00637   bool escSeq = false;
00638   const char *p;
00639 
00640   for (p = str; *p; ++p) {
00641     if (escSeq && *p == 'm')
00642       escSeq = false;
00643     else
00644       if (*p == '\033')
00645         escSeq = true;
00646       else
00647         if (!escSeq)
00648           ++len;
00649   }
00650   return len;
00651 }

Generated on Thu Sep 6 20:11:25 2007 for Pylon Application Platform by  doxygen 1.5.1