00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <climits>
00020 #include <cstdarg>
00021 #include <cmath>
00022 #include <cfloat>
00023 #include <cstdlib>
00024 #include "ncl/nxsdefs.h"
00025 #include "ncl/nxsstring.h"
00026
00027 using namespace std;
00028
00029
00030
00031
00032 void NxsString::split(const std::string &s, std::list<std::string> * r)
00033 {
00034 NCL_ASSERT(r);
00035 if (r == NULL)
00036 return;
00037 std::string current;
00038 for (std::string::const_iterator sIt = s.begin(); sIt != s.end(); ++sIt)
00039 {
00040 const char c = *sIt;
00041 if (isgraph(c))
00042 current.append(1, c);
00043 else if (!current.empty())
00044 {
00045 r->push_back(current);
00046 current.clear();
00047 }
00048 }
00049 if (!current.empty())
00050 r->push_back(current);
00051 }
00052
00053 int NxsString::index_in_vector(const std::string &t, const std::vector<std::string> &v)
00054 {
00055 std::vector<std::string>::const_iterator vIt = v.begin();
00056 int i = 0;
00057 for (; vIt != v.end(); ++vIt, ++i)
00058 {
00059 if (t == *vIt)
00060 return i;
00061 }
00062 return -1;
00063 }
00064
00065 int NxsString::index_in_array(const std::string &t, const char * * v, const unsigned n)
00066 {
00067 if (n > 0 && v)
00068 {
00069 for (int i = 0; i < (int) n; ++i)
00070 {
00071 if (v[i] && t == v[i])
00072 return i;
00073 }
00074 }
00075 return -1;
00076 }
00077
00078
00080 std::string NxsString::strip_surrounding_whitespace(const std::string & s)
00081 {
00082 std::string l = strip_leading_whitespace(s);
00083 return strip_trailing_whitespace(l);
00084 }
00085
00086 std::string NxsString::strip_leading_whitespace(const std::string & s)
00087 {
00088 std::string t;
00089 t.reserve(s.length());
00090 bool graphFound = false;
00091 for (std::string::const_iterator sIt = s.begin(); sIt != s.end(); ++sIt)
00092 {
00093 if (graphFound || isgraph(*sIt))
00094 {
00095 t.push_back(*sIt);
00096 graphFound = true;
00097 }
00098 }
00099 return t;
00100 }
00101
00102
00103 std::string NxsString::strip_trailing_whitespace(const std::string & s)
00104 {
00105 std::string t;
00106 t.reserve(s.length());
00107 bool graphFound = false;
00108 for (std::string::const_reverse_iterator sIt = s.rbegin(); sIt != s.rend(); ++sIt)
00109 {
00110 if (graphFound || isgraph(*sIt))
00111 {
00112 t.push_back(*sIt);
00113 graphFound = true;
00114 }
00115 }
00116 return std::string(t.rbegin(), t.rend());
00117 }
00118
00120 std::string NxsString::strip_whitespace(const std::string & s)
00121 {
00122 std::string t;
00123 t.reserve(s.length());
00124 for (std::string::const_iterator sIt = s.begin(); sIt != s.end(); ++sIt)
00125 {
00126 if (isgraph(*sIt))
00127 t.push_back(*sIt);
00128 }
00129 return t;
00130 }
00131
00136 bool NxsString::to_long(const char *o, long *n)
00137 {
00138 if (o == NULL)
00139 return false;
00140 if (strchr("0123456789-+",*o) != NULL)
00141 {
00142 char * pEnd;
00143 const long i = strtol (o, &pEnd, 10);
00144 if (*pEnd != '\0')
00145 return false;
00146 if (n != NULL)
00147 *n = i;
00148 return true;
00149 }
00150 return false;
00151 }
00152
00157 bool NxsString::to_double(const char *o, double *n)
00158 {
00159 if (o == NULL)
00160 return false;
00161 if (strchr("0123456789-.+",*o) != NULL )
00162 {
00163 char * pEnd;
00164 const double i = strtod (o, &pEnd);
00165 if (*pEnd != '\0')
00166 return false;
00167 if (n != NULL)
00168 *n = i;
00169 return true;
00170 }
00171 return false;
00172 }
00173
00174 bool NxsString::case_insensitive_equals(const char *o, const char * t)
00175 {
00176 if (o == 0L || t == 0L)
00177 return false;
00178 for (; toupper(*o) == toupper(*t); ++o, ++t)
00179 {
00180 if (*o == '\0')
00181 return true;
00182 }
00183 return false;
00184 }
00185
00189 std::string & NxsString::to_upper(std::string &s)
00190 {
00191 for (std::string::iterator sIt = s.begin(); sIt != s.end(); sIt++)
00192 *sIt = (char) toupper(*sIt);
00193 return s;
00194 }
00198 std::string & NxsString::to_lower(std::string &s)
00199 {
00200 for (std::string::iterator sIt = s.begin(); sIt != s.end(); sIt++)
00201 *sIt = (char) tolower(*sIt);
00202 return s;
00203 }
00204
00208 NxsString &NxsString::operator+=(
00209 const double d)
00210 {
00211 char tmp[81];
00212
00213
00214
00215
00216 sprintf(tmp, "%#3.6f", d);
00217 unsigned tmplen = (unsigned)strlen(tmp);
00218
00219
00220
00221 for (;;)
00222 {
00223 if (tmplen < 3 || tmp[tmplen-1] != '0' || tmp[tmplen-2] == '.')
00224 break;
00225 tmp[tmplen-1] = '\0';
00226 tmplen--;
00227 }
00228
00229 append(tmp);
00230 return *this;
00231 }
00232
00236 NxsString &NxsString::AddTail(
00237 char c,
00238 unsigned n)
00239 {
00240 char s[2];
00241 s[0] = c;
00242 s[1] = '\0';
00243
00244 for (unsigned i = 0; i < n; i++)
00245 append(s);
00246
00247 return *this;
00248 }
00249
00250
00260 int NxsString::PrintF(
00261 const char *formatStr,
00262 ...)
00263 {
00264 const int kInitialBufferSize = 256;
00265 char buf[kInitialBufferSize];
00266
00267
00268
00269 va_list argList;
00270
00271
00272
00273
00274 va_start(argList, formatStr);
00275
00276
00277
00278
00279 int nAdded = vsnprintf(buf, kInitialBufferSize, formatStr, argList);
00280
00281
00282
00283 va_end(argList);
00284
00285
00286
00287
00288
00289 if (nAdded < 0 || nAdded >= kInitialBufferSize)
00290 buf[kInitialBufferSize - 1] = '\0';
00291
00292 *this << buf;
00293
00294 return nAdded;
00295 }
00296
00300 bool NxsString::IsStdAbbreviation(
00301 const NxsString &s,
00302 bool respectCase)
00303 const
00304 {
00305 if (empty())
00306 return false;
00307
00308
00309
00310 const unsigned slen = static_cast<unsigned long>(s.size());
00311
00312
00313
00314 const unsigned tlen = static_cast<unsigned long>(size());
00315
00316
00317
00318 if (tlen > slen)
00319 return false;
00320
00321
00322
00323
00324 for (unsigned k = 0; k < tlen; k++)
00325 {
00326 if (respectCase)
00327 {
00328 if ((*this)[k] != s[k])
00329 return false;
00330 }
00331 else if (toupper((*this)[k]) != toupper(s[k]))
00332 return false;
00333 }
00334
00335 return true;
00336 }
00337
00344 bool NxsString::IsCapAbbreviation(
00345 const NxsString &s)
00346 const
00347 {
00348 if (empty())
00349 return false;
00350
00351
00352
00353 const unsigned slen = static_cast<unsigned>(s.size());
00354
00355
00356
00357 const unsigned tlen = static_cast<unsigned>(size());
00358
00359
00360
00361 if (tlen > slen)
00362 return false;
00363
00364 unsigned k = 0;
00365 for (; k < slen; k++)
00366 {
00367 if (isupper(s[k]))
00368 {
00369
00370
00371
00372 if (k >= tlen)
00373 return false;
00374
00375
00376
00377
00378 char tokenChar = (char)toupper((*this)[k]);
00379 if (tokenChar != s[k])
00380 return false;
00381 }
00382 else if (!isalpha(s[k]))
00383 {
00384
00385
00386
00387
00388
00389
00390
00391
00392
00393 if (k >= tlen)
00394 return false;
00395
00396 if ((*this)[k] != s[k])
00397 return false;
00398 }
00399 else
00400 {
00401
00402
00403
00404
00405 break;
00406 }
00407 }
00408
00409
00410
00411
00412
00413 for (; k < tlen; k++)
00414 {
00415 const char tokenChar = (char)toupper((*this)[k]);
00416 const char otherChar = (char)toupper(s[k]);
00417 if (tokenChar != otherChar)
00418 return false;
00419 }
00420
00421 return true;
00422 }
00423
00429 NxsString &NxsString::RightJustifyLong(
00430 long x,
00431 unsigned int w,
00432 bool clear_first)
00433 {
00434 bool x_negative = (x < 0L ? true : false);
00435 unsigned long xabs = (x_negative ? (-x) : x);
00436 unsigned num_spaces = w;
00437
00438
00439
00440
00441
00442 unsigned x_width = (x == 0 ? 1 :1 + (int)log10((double)xabs));
00443 if (x_negative)
00444 x_width++;
00445
00446 NCL_ASSERT(x_width <= num_spaces);
00447 num_spaces -= x_width;
00448
00449 if (clear_first)
00450 erase();
00451
00452 for (unsigned k = 0; k < num_spaces; k++)
00453 *this += ' ';
00454
00455 if (x_negative)
00456 *this += '-';
00457
00458 *this += xabs;
00459 return *this;
00460 }
00461
00467 NxsString &NxsString::RightJustifyDbl(
00468 double x,
00469 unsigned w,
00470 unsigned p,
00471 bool clear_first)
00472 {
00473 if (clear_first)
00474 erase();
00475
00476 char fmtstr[81];
00477 sprintf(fmtstr, "%%.%df", p);
00478 NxsString tmp;
00479 tmp.PrintF(fmtstr, x);
00480
00481 NCL_ASSERT(w >= tmp.length());
00482 unsigned num_spaces = w - tmp.length();
00483
00484 for (unsigned k = 0; k < num_spaces; k++)
00485 *this += ' ';
00486
00487 *this += tmp;
00488 return *this;
00489 }
00490
00496 NxsString &NxsString::RightJustifyString(
00497 const NxsString &s,
00498 unsigned w,
00499 bool clear_first)
00500 {
00501 if (clear_first)
00502 erase();
00503
00504 NCL_ASSERT(w >= s.length());
00505 unsigned num_spaces = w - s.length();
00506
00507 for (unsigned k = 0; k < num_spaces; k++)
00508 *this += ' ';
00509
00510 *this += s;
00511 return *this;
00512 }
00513 void NxsString::blanks_to_underscores(std::string &s)
00514 {
00515 for (std::string::iterator sIt = s.begin(); sIt != s.end(); sIt++)
00516 {
00517 if (*sIt == ' ')
00518 *sIt = '_';
00519 }
00520 }
00521
00522 void NxsString::add_nxs_quotes(std::string &s)
00523 {
00524 std::string withQuotes;
00525 unsigned len = (unsigned)s.length();
00526 withQuotes.reserve(len + 4);
00527 withQuotes.append(1,'\'');
00528 for (std::string::const_iterator sIt = s.begin(); sIt != s.end(); sIt++)
00529 {
00530 withQuotes.append(1, *sIt);
00531 if (*sIt == '\'')
00532 withQuotes.append(1,'\'');
00533 }
00534 withQuotes.append(1,'\'');
00535 s.swap(withQuotes);
00536 }
00537
00538 NxsString::NxsQuotingRequirements NxsString::determine_quoting_requirements(const std::string & s)
00539 {
00540 NxsQuotingRequirements nrq = kNoQuotesNeededForNexus;
00541 for (std::string::const_iterator sIt = s.begin(); sIt != s.end(); ++sIt)
00542 {
00543 if (!isgraph(*sIt))
00544 {
00545 if (*sIt != ' ')
00546 return kSingleQuotesNeededForNexus;
00547 nrq = kUnderscoresSufficeForNexus;
00548 }
00549 else if (strchr("(){}\"-]/\\,;:=*`+<>", *sIt) != NULL)
00550 {
00551
00552
00553
00554
00555 return (s.length() > 1 ? kSingleQuotesNeededForNexus : kNoQuotesNeededForNexus);
00556 }
00557 else if (strchr("\'[_", *sIt) != NULL)
00558 {
00559
00560
00561
00562 return kSingleQuotesNeededForNexus;
00563 }
00564 }
00565 return nrq;
00566 }
00567
00571 bool NxsString::QuotesNeeded() const
00572 {
00573 for (NxsString::const_iterator sIt = begin(); sIt != end(); sIt++)
00574 {
00575 char c = (*sIt);
00576 if (!isgraph(c))
00577 return true;
00578 else if (strchr("(){}\"-]/\\,;:=*`+<>", c) != NULL && length() > 1)
00579 return true;
00580 else if (c == '\'' || c == '_' || c == '[')
00581 return true;
00582 }
00583 return false;
00584 }
00585
00589 NxsString &NxsString::BlanksToUnderscores()
00590 {
00591 unsigned len = (unsigned)length();
00592 for (unsigned k = 0; k < len; k++)
00593 {
00594 char &ch = at(k);
00595 if (ch == ' ')
00596 ch = '_';
00597 }
00598 return *this;
00599 }
00600
00604 NxsString &NxsString::UnderscoresToBlanks()
00605 {
00606 unsigned len = (unsigned)length();
00607 for (unsigned k = 0; k < len; k++)
00608 {
00609 char &ch = at(k);
00610 if (ch == '_')
00611 ch = ' ';
00612 }
00613 return *this;
00614 }
00615
00622 NxsString &NxsString::ShortenTo(
00623 unsigned n)
00624 {
00625 NCL_ASSERT(n > 3);
00626 if (length() <= static_cast<unsigned>(n))
00627 return *this;
00628
00629 NxsString s;
00630 for (NxsString::iterator sIt = begin(); sIt != end(); sIt++)
00631 {
00632 s += (*sIt);
00633 if (s.length() >= n - 3)
00634 break;
00635 }
00636 s += "...";
00637
00638 *this = s;
00639 return *this;
00640 }
00641
00642
00646 bool NxsString::IsADouble() const
00647 {
00648 const char *str = c_str();
00649 unsigned i = 0;
00650 bool hadDecimalPt = false;
00651 bool hadExp = false;
00652 bool hadDigit = false;
00653 bool hadDigitInExp = false;
00654
00655
00656
00657 if (str[i]=='-' || str[i] == '+')
00658 i++;
00659
00660 while (str[i])
00661 {
00662 if (isdigit(str[i]))
00663 {
00664
00665
00666 if (hadExp)
00667 hadDigitInExp = true;
00668 else
00669 hadDigit = true;
00670 }
00671 else if (str[i] == '.')
00672 {
00673
00674
00675 if (hadExp || hadDecimalPt)
00676 return false;
00677 hadDecimalPt = true;
00678 }
00679 else if (str[i] == 'e' || str[i] == 'E')
00680 {
00681
00682
00683 if (hadExp || !hadDigit)
00684 return false;
00685 hadExp = true;
00686 }
00687 else if (str[i] == '-')
00688 {
00689
00690
00691 if (!hadExp || (str[i-1] != 'e' && str[i-1] != 'E') )
00692 return false;
00693 }
00694 else
00695 return false;
00696 i++;
00697 }
00698
00699 if (hadExp)
00700 {
00701 if (hadDigitInExp)
00702 return true;
00703 return false;
00704 }
00705
00706 if (hadDigit)
00707 return true;
00708 return false;
00709 }
00710
00714 bool NxsString::IsALong() const
00715 {
00716 const char *str = c_str();
00717 unsigned i = 0;
00718
00719
00720
00721 if (str[i]=='-')
00722 i++;
00723
00724 if (!isdigit(str[i]))
00725 return false;
00726
00727 while (str[i])
00728 {
00729 if (!isdigit(str[i]))
00730 return false;
00731 i++;
00732 }
00733
00734 return true;
00735 }
00736
00741 bool NxsString::EqualsCaseInsensitive(
00742 const NxsString &s)
00743 const
00744 {
00745 unsigned k;
00746 unsigned slen = (unsigned)s.size();
00747 unsigned tlen = (unsigned)size();
00748 if (slen != tlen)
00749 return false;
00750
00751 for (k = 0; k < tlen; k++)
00752 {
00753 if ((char)toupper((*this)[k]) != (char)toupper(s[k]))
00754 return false;
00755 }
00756
00757 return true;
00758 }
00759
00765 NxsString NxsString::ToHex(
00766 long p,
00767 unsigned nFours)
00768 {
00769 NxsString s;
00770 char decod[] = "0123456789ABCDEF";
00771 for (int i = nFours - 1; i >= 0 ; i--)
00772 {
00773 unsigned long k = (p >> (4*i));
00774 unsigned long masked = (k & 0x000f);
00775 s += decod[masked];
00776 }
00777 return s;
00778 }
00779
00784 NxsString NxsString::UpperCasePrefix() const
00785 {
00786 NxsString x;
00787 unsigned i = 0;
00788 while (i < size() && isupper((*this)[i]))
00789 x += (*this)[i++];
00790 return x;
00791 }
00792
00797 unsigned NxsString::ConvertToUnsigned() const
00798 {
00799 long l = ConvertToLong();
00800 if (l < 0 || l >= (long) INT_MAX)
00801 return UINT_MAX;
00802 return static_cast<unsigned> (l);
00803 }
00804
00809 int NxsString::ConvertToInt() const
00810 {
00811 long l = ConvertToLong();
00812 if (l == LONG_MAX || l > INT_MAX)
00813 return INT_MAX;
00814 if (l == -LONG_MAX || l <-INT_MAX)
00815 return -INT_MAX;
00816 return static_cast<int> (l);
00817 }
00818
00823 long NxsString::ConvertToLong() const
00824 {
00825 if (length() == 0 || !(isdigit(at(0)) || at(0) == '-'))
00826 throw NxsX_NotANumber();
00827 const char *b = c_str();
00828 char *endP;
00829 long l = strtol(b, &endP, 10);
00830 #if defined(_MSC_VER)
00831 if ((l == 0 && (endP - b) == 0))
00832 throw NxsX_NotANumber();
00833 #else
00834 if ((l == 0 && ((long) endP - (long) b) == 0))
00835 throw NxsX_NotANumber();
00836 #endif
00837 return l;
00838 }
00839
00844 double NxsString::ConvertToDouble() const
00845 {
00846 if (length() == 0)
00847 throw NxsX_NotANumber();
00848
00849 char ch = at(0);
00850 if (isdigit(ch) || ch == '-' || ch == '.'|| toupper(ch) == 'E')
00851 {
00852 const char *b = c_str();
00853 char *endP;
00854 double d = strtod(b, &endP);
00855 #if defined(_MSC_VER)
00856 if ((d == 0.0 && (endP - b) == 0))
00857 throw NxsX_NotANumber();
00858 #else
00859 if ((d == 0.0 && ((long) endP - (long) b) == 0))
00860 throw NxsX_NotANumber();
00861 #endif
00862 if (d == HUGE_VAL)
00863 return DBL_MAX;
00864 if (d == -HUGE_VAL)
00865 return -DBL_MAX;
00866 return d;
00867 }
00868 throw NxsX_NotANumber();
00869 #if defined (DEMANDS_UNREACHABLE_RETURN)
00870 return DBL_MAX;
00871 #endif
00872 }
00873
00879 bool SetToShortestAbbreviation(
00880 NxsStringVector &strVec,
00881 bool allowTooShort)
00882 {
00883 NxsStringVector upperCasePortion;
00884 unsigned i;
00885 for (i = 0; i < strVec.size(); i++)
00886 {
00887
00888
00889 strVec[i].ToLower();
00890
00891 unsigned prefLen = 0;
00892 NxsString pref;
00893
00894 if (prefLen >= strVec[i].size())
00895 return false;
00896 pref += (char) toupper(strVec[i][prefLen++]);
00897 bool moreChars = true;
00898
00899
00900
00901
00902 for (;moreChars;)
00903 {
00904 unsigned prevInd = 0;
00905 for (; prevInd < upperCasePortion.size(); prevInd++)
00906 {
00907 if (pref == upperCasePortion[prevInd])
00908 {
00909
00910
00911 if (prefLen >= strVec[i].size())
00912 {
00913 if (allowTooShort)
00914 {
00915 if (prefLen < strVec[prevInd].size())
00916 upperCasePortion[prevInd] += (char) toupper(strVec[prevInd][prefLen]);
00917 moreChars = false;
00918 break;
00919 }
00920 else
00921 return false;
00922 }
00923 pref += (char) toupper(strVec[i][prefLen]);
00924 if (prefLen >= strVec[prevInd].size())
00925 {
00926 if (allowTooShort)
00927 {
00928 prevInd = 0;
00929 prefLen++;
00930 break;
00931 }
00932 else
00933 return false;
00934 }
00935 upperCasePortion[prevInd] += (char) toupper(strVec[prevInd][prefLen++]);
00936 prevInd = 0;
00937 break;
00938 }
00939 else
00940 {
00941 unsigned j;
00942 for (j = 0; j < prefLen; j++)
00943 {
00944 if (pref[j] != upperCasePortion[prevInd][j])
00945 break;
00946 }
00947 if (j == prefLen)
00948 {
00949
00950
00951 if (prefLen >= strVec[i].size())
00952 {
00953 if (allowTooShort)
00954 {
00955 moreChars = false;
00956 break;
00957 }
00958 else
00959 return false;
00960 }
00961 pref += (char) toupper(strVec[i][prefLen++]);
00962 break;
00963 }
00964 }
00965 }
00966 if (prevInd == upperCasePortion.size() || !moreChars)
00967 {
00968
00969
00970
00971 upperCasePortion.push_back(pref);
00972 break;
00973 }
00974 }
00975 }
00976
00977 for (i = 0; i < strVec.size(); i++)
00978 {
00979 for (unsigned j = 0; j < upperCasePortion[i].size(); j++)
00980 strVec[i][j] = upperCasePortion[i][j];
00981 }
00982
00983 return true;
00984 }
00985
00989 NxsStringVector GetVecOfPossibleAbbrevMatches(
00990 const NxsString &testStr,
00991 const NxsStringVector &possMatches)
00992 {
00993 NxsStringVector matches;
00994 for (unsigned i = 0; i < possMatches.size(); i++)
00995 {
00996 if (testStr.Abbreviates(possMatches[i]))
00997 matches.push_back(possMatches[i]);
00998 }
00999 return matches;
01000 }
01001
01006 NxsStringVector BreakPipeSeparatedList(
01007 const NxsString &strList)
01008 {
01009 NxsString::const_iterator p = strList.begin();
01010 NxsString ss;
01011 NxsStringVector retVec;
01012 for (;;)
01013 {
01014 bool done = (p == strList.end());
01015 if (done || (*p == '|'))
01016 {
01017 retVec.push_back(ss);
01018 ss.clear();
01019 if (done)
01020 break;
01021 p++;
01022 }
01023 ss += *p;
01024 p++;
01025 }
01026 return retVec;
01027 }