Humble Framework for SkyOS


Main Page | Modules | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

HString.h

Go to the documentation of this file.
00001 /****************************************************************************
00002 **
00003 **  $Header: /SkyOS.root/HFramework/HString.h 6     4/17/05 12:29p Lee Neuse $
00004 **
00005 ****************************************************************************/
00011 #ifndef HSTRING_H
00012     #define HSTRING_H
00013 
00014 #include <cctype>
00024 class HString : public HObj
00025     {
00026     typedef HObj        base_class;
00027     static StringPtr    ClassName(void) { return "HString"; }
00028 /*  ----------------------------------------------------------------------
00029     VARIABLES
00030     ----------------------------------------------------------------------  */
00031 public:
00032     typedef enum    {   
00033                     ALIGN_DEFAULT   = 0, 
00034                     ALIGN_LEFT      = 0x01, 
00035                     ALIGN_CENTER    = 0x02, 
00036                     ALIGN_RIGHT     = 0x03
00037                     }   Alignment;
00038 protected:
00039     std::string         m_str;
00040 /*  ----------------------------------------------------------------------
00041     CTOR / DTOR
00042     ----------------------------------------------------------------------  */
00043 public:
00044     HString(void)
00045         { m_str.clear(); }
00046         
00047     HString(StringPtr pstr) : m_str(pstr)
00048         { /* EMPTY CTOR */ }
00049 
00050     HString(const HString & rhs) : m_str(rhs.m_str)
00051         { /* EMPTY CTOR */ }
00052 
00053     virtual ~HString()
00054         { /* EMPTY DTOR */ }
00055 /*  ----------------------------------------------------------------------
00056     METHODS
00057     ----------------------------------------------------------------------  */
00058 public:
00067     static uint32               
00068     Hash(StringPtr pstr)
00069         {
00070         uint32      uCRC = 0X811C9DC5L; // initialize to "magic number"
00071         
00072         while (STR_VALID(pstr))
00073             {
00074             uCRC *= 0x01000193L;        // multiply by the 32 bit FNV magic prime
00075             uCRC ^= uint32( *pstr++ );  // xor the bottom with the current octet
00076             }
00077 
00078         return uCRC;
00079         }
00087     HString &
00088     Align(HString::Alignment align, uint32 uWidth, Text chPad = ' ') throw()
00089         {
00090         (void) HError::NoError();
00091 
00092         ASSERT(uWidth > 0);
00093         
00094         (void) Trim();
00095         
00096         switch (align)
00097             {
00098             case ALIGN_DEFAULT: // alignment defaults to "left"
00099             case ALIGN_LEFT:
00100                 if (uWidth > m_str.size()) 
00101                     m_str.append( (uWidth - m_str.size()), chPad);
00102                 break;
00103 
00104             case ALIGN_RIGHT:
00105                 if (uWidth > m_str.size())
00106                     m_str.insert(m_str.begin(), (uWidth - m_str.size()), chPad);
00107                 break;
00108             
00109             case ALIGN_CENTER:
00110                 if (uWidth > m_str.size())
00111                     {
00112                     uint32  uPadding = uWidth - m_str.size();
00113         
00114                     m_str.append( (uPadding / 2), chPad);
00115                     m_str.insert( m_str.begin(), (uPadding - (uPadding / 2)), chPad);
00116                     }
00117                 break;
00118             
00119             default:
00120                 HError::Throw(ERR_BAD_PARAMETER, __FILE__, __LINE__);
00121             }
00122 
00123         return *this;
00124         }       
00131     ErrCode             
00132     Append(StringPtr pstr)
00133         {
00134         if (STR_VALID(pstr))
00135             m_str += pstr;
00136         return HError::NoError();
00137         }
00145     int32               
00146     Compare(const HString & rhs, bool bCase = true) const
00147         {
00148         if (&rhs == this) return 0; // we are always equal to ourself
00149 
00150         return bCase ?  Humble::safe_strcmp(m_str.c_str(), rhs.m_str.c_str()) :
00151                         Humble::safe_strcmpi(m_str.c_str(), rhs.m_str.c_str());
00152         }
00160     int32               
00161     Compare(StringPtr pstr, bool bCase = true) const
00162         {
00163         if (m_str.c_str() == pstr) return 0;    // we are always equal to ourself
00164 
00165         return bCase ?  Humble::safe_strcmp(m_str.c_str(), pstr) :
00166                         Humble::safe_strcmpi(m_str.c_str(), pstr);
00167         }
00178     int32
00179     Find(Text ch, uint32 uStart = 0) const
00180         {
00181         std::string::size_type  sPos;
00182         
00183         if (!isValidIndex(uStart))  return -1;
00184         
00185         sPos = (uStart == 0) ? m_str.find(ch) : m_str.find(ch, uStart);
00186         
00187         return (sPos == std::string::npos) ? -1 : int32(sPos);
00188         }
00199     int32
00200     Find(StringPtr pstr, uint32 uStart = 0) const
00201         {
00202         std::string::size_type  sPos;
00203         
00204         if (STR_EMPTY(pstr) || !isValidIndex(uStart))
00205             return -1;
00206         
00207         sPos = (uStart == 0) ? m_str.find(pstr) : m_str.find(pstr, uStart);
00208         
00209         return (sPos == std::string::npos) ? -1 : int32(sPos);
00210         }
00220     int32
00221     FindLast(Text ch) const
00222         {
00223         std::string::size_type sPos = m_str.rfind(ch);
00224         
00225         return (sPos == std::string::npos) ? -1 : int32(sPos);
00226         }
00236     int32
00237     FindLast(StringPtr pstr) const
00238         {
00239         std::string::size_type  sPos;
00240         
00241         if (STR_EMPTY(pstr) ||
00242             (sPos = m_str.rfind(pstr)) == std::string::npos)
00243             {
00244             return -1;
00245             }
00246             
00247         return int32(sPos);
00248         }
00258 #ifndef DOXYGEN_SHOULD_SKIP_THIS
00259     GCC_ONLY( __attribute__ ((format (printf,2,3))) )
00260 #endif
00261     int32
00262     Format(StringPtr pstrFormat, ...)
00263         {
00264         if (STR_VALID(pstrFormat))
00265             {
00266             va_list     vaList;
00267             
00268             va_start(vaList, pstrFormat);
00269             (void) FormatV(pstrFormat, vaList);
00270             va_end(vaList);
00271             }
00272         else
00273             SetEmpty();
00274     
00275         return GetLength();
00276         }
00288     int32
00289     FormatV(StringPtr pstrFormat, va_list & vaList)
00290         {
00291         if (STR_EMPTY(pstrFormat))  
00292             {
00293             DEBUG_LOG("Hstring::FormatV() => NULL format string.\n");
00294             SetEmpty();
00295             return 0;
00296             }
00297         //
00298         // 312 == strlen("-1+(309 zeroes).")
00299         // 309 zeroes => max precision of a double
00300         // 6 => adjustment in case precision is not specified, 
00301         //      which means that the precision defaults to 6
00302         //
00303         const int32 kMaxIntLen      = 40;
00304         const int32 kMaxFloatLen    = 312 + 6;
00305         //
00306         //  Time for some voodoo...figure out how long to make the buffer.
00307         //
00308         va_list     argList;
00309         int32       nLen,
00310                     nItemLen,
00311                     nMaxLen = 0;
00312         int         nPrecision,     // these have to be "real" int variables, or
00313                     nWidth;         // gcc complains about the sprintf() below
00314 
00315         argList = vaList;
00316         for (StringPtr pstr = pstrFormat; STR_VALID(pstr); ++pstr)
00317             {
00318             // handle '%' character, but watch out for '%%'
00319             if (*pstr != '%' || *(pstr + 1) == '%')
00320                 {
00321                 nMaxLen++;
00322                 continue;
00323                 }
00324 
00325             nItemLen = nWidth = 0;
00326             // handle '%' character with format
00327             for (pstr++ ; STR_VALID(pstr); ++pstr)
00328                 {
00329                 // check for valid flags
00330                 if (*pstr == '#')
00331                     nMaxLen += 2;   // for '0x'
00332                 else if (*pstr == '*')
00333                     nWidth = va_arg(argList, int);
00334                 else if (*pstr == '-' || *pstr == '+' || *pstr == '0' || *pstr == ' ')
00335                     ;
00336                 else // hit non-flag character
00337                     break;
00338                 }
00339             //
00340             //  Get width
00341             //
00342             if (nWidth == 0)
00343                 {
00344                 nWidth = Humble::safe_strtoi(pstr);
00345                 while (STR_VALID(pstr) && isdigit(*pstr))
00346                     pstr++;
00347                 }
00348 
00349             ASSERT(nWidth >= 0);
00350             //
00351             //  Get precision
00352             //
00353             nPrecision = 0;
00354             if (*pstr == '.')
00355                 {
00356                 pstr++; // skip past '.' separator (width.precision)
00357                 if (*pstr == '*')
00358                     {
00359                     nPrecision = va_arg(argList, int);
00360                     pstr++;
00361                     }
00362                 else
00363                     {
00364                     nPrecision = Humble::safe_strtoi(pstr);
00365                     while (STR_VALID(pstr) && isdigit(*pstr))
00366                         pstr++;
00367                     }
00368 
00369                 ASSERT(nPrecision >= 0);
00370                 }
00371             //
00372             //  Get modifier -- it's ignored, but needs to be handled
00373             //
00374             switch (*pstr)
00375                 {
00376                 case 'l':
00377                 case 'h':
00378                     pstr++; // skip past modifier
00379                     break;
00380                 }
00381             //
00382             //  pstr now points to specifier
00383             //
00384             switch (*pstr)
00385                 {
00386                 // single character
00387                 case 'c':
00388                     nItemLen = 2;
00389                     (void) va_arg(argList, Text);
00390                     break;
00391                 // string
00392                 case 's':
00393                     {
00394                     StringPtr pstrNextArg = va_arg(argList, StringPtr);
00395                     
00396                     if (NULL_PTR(pstrNextArg))
00397                         nItemLen = 6;  // "(null)"
00398                     else
00399                         {
00400                         nItemLen = STR_LEN(pstrNextArg);
00401                         nItemLen = max(1, nItemLen);
00402                         }
00403                     }
00404                     break;
00405                 }
00406             //
00407             // adjust nItemLen for strings
00408             //
00409             if (nItemLen != 0)
00410                 {
00411                 nItemLen = max(nItemLen, nWidth);
00412                 if (nPrecision != 0)
00413                     nItemLen = min(nItemLen, nPrecision);
00414                 }
00415             else
00416                 {
00417                 switch (*pstr)
00418                     {
00419                     // integers
00420                     case 'd':
00421                     case 'i':
00422                     case 'u':
00423                     case 'x':
00424                     case 'X':
00425                     case 'o':
00426                         (void) va_arg(argList, int);
00427                         nItemLen = max(kMaxIntLen, nWidth + nPrecision);
00428                         break;
00429 
00430                     case 'e':
00431                     case 'E':
00432                     case 'g':
00433                     case 'G':
00434                         (void) va_arg(argList, double);
00435                         nItemLen = max(128, nWidth + nPrecision);   // why 128?
00436                         break;
00437 
00438                     case 'f':
00439                         {
00440                         Text    szTmp[kMaxFloatLen];
00441                         
00442                         nItemLen = nWidth + nPrecision;
00443                         if (nItemLen < kMaxFloatLen)
00444                             {
00445                             nItemLen = STR_SPRINTF( szTmp, kMaxFloatLen,
00446                                                     "%*.*f", 
00447                                                     nWidth, nPrecision + 6, va_arg(argList, double));
00448                             }
00449                         }
00450                         break;
00451 
00452                     case 'p':
00453                         (void) va_arg(argList, void *);
00454                         nItemLen = max(kMaxIntLen, nWidth + nPrecision);
00455                         break;
00456 
00457                     // no output
00458                     case 'n':
00459                         (void) va_arg(argList, int*);
00460                         break;
00461 
00462                     default:  // unknown formatting option
00463                         ASSERT(0);  //lint !e506
00464                     }
00465                 }
00466         
00467             nMaxLen += nItemLen;    // adjust nMaxLen for output nItemLen
00468             }
00469         //
00470         //  Format the string.  SInce most of the strings are expected to be
00471         //  short, anything with a length of 512 or less is formatted using a
00472         //  stack-based buffer.  Larger strings are handled by allocating and
00473         //  later freeing a dynamic buffer.
00474         //
00475         if (nMaxLen < 512)  
00476             {
00477             Text    szBuffer[512] = { '\0' };
00478             
00479             nLen = Humble::safe_vsprintf(szBuffer, nMaxLen, pstrFormat, vaList);
00480             m_str = szBuffer;
00481             }
00482         else    // large strings are dynamically allocated
00483             {
00484             TextPtr     pstr = new Text[ nMaxLen+1 ];
00485 
00486             ASSERT_PTR(pstr);
00487             DEBUG_LOG(  "HString::FormatV() => allocated %ld byte string.\n",
00488                         (nMaxLen+1));
00489 
00490             nLen = Humble::safe_vsprintf(pstr, nMaxLen, pstrFormat, vaList);
00491             m_str = pstr;
00492 
00493             delete [] pstr;
00494             }
00495 
00496 #if __DEBUG__
00497         if (nLen > nMaxLen)
00498             {
00499             DEBUG_LOG(  "HString::FormatV() => actual length of \"%s\" is %ld (estimated as %ld).\n",
00500                         m_str.c_str(), nLen, nMaxLen);
00501             }
00502 #endif
00503         
00504         return nLen;
00505         }
00516     HString 
00517     Left(uint32 uCount) const
00518         {
00519         std::string str;
00520         uint32      uLen = GetLength();
00521 
00522         if (uCount >= uLen)
00523             str = m_str;
00524         else if (uCount > 0)
00525             str = m_str.substr(0, uCount);
00526         
00527         return HString(str.c_str());
00528         }
00533     HString &
00534     MakeLower(void)
00535         {
00536         for (uint32 udx = 0; udx < m_str.length(); ++udx)
00537             m_str[udx] = tolower( m_str[udx] );
00538 
00539 //      std::transform( m_str.begin(), m_str.end(), m_str.begin(), std::tolower);
00540         return *this;
00541         }
00546     HString &
00547     MakeUpper(void)
00548         {
00549         for (uint32 udx = 0; udx < m_str.length(); ++udx)
00550             m_str[udx] = toupper( m_str[udx] );
00551 
00552 //      std::transform( m_str.begin(), m_str.end(), m_str.begin(), std::toupper);
00553 
00554         return *this;
00555         }
00567     HString 
00568     Mid(uint32 uStart, int32 nCount = -1) const
00569         {
00570         std::string str;
00571         
00572         if (isValidIndex(uStart))
00573             {
00574             if (nCount < 0 || nCount > int32(GetLength() - uStart))
00575                 nCount = int32(GetLength() - uStart);
00576                 
00577             if (nCount > 0)
00578                 str = m_str.substr(uStart, nCount);
00579             }
00580         
00581         return HString(str.c_str());
00582         }
00593     int32
00594     Replace(Text chOld, Text chNew)
00595         {
00596         std::string::iterator   it;     
00597         int32                   nCount = 0;
00598 
00599         for (it = m_str.begin(); it != m_str.end(); ++it)
00600             if (*it == chOld)
00601                 {
00602                 *it = chNew;
00603                 nCount++;
00604                 }
00605 
00606         return nCount;
00607         }
00618     HString 
00619     Right(int32 nCount) const
00620         {
00621         std::string str;
00622         int32       nLen = GetLength();
00623 
00624         if (nCount >= nLen)
00625             str = m_str;
00626         else if (nCount > 0)
00627             str = m_str.substr(nLen - nCount);
00628         
00629         return HString(str.c_str());
00630         }
00635     HString &
00636     Trim(void)
00637         { 
00638         TrimRight(); 
00639         TrimLeft(); 
00640         return *this;
00641         }
00646     HString &
00647     TrimLeft(void)
00648         {
00649         while (!m_str.empty() && std::isspace( m_str[0] ))
00650             m_str.erase( m_str.begin() );
00651             
00652         return *this;
00653         }
00658     HString &
00659     TrimRight(void)
00660         {
00661         while (!m_str.empty() && std::isspace( m_str[m_str.size() - 1] ))
00662             m_str.erase(m_str.end() - 1);
00663 
00664         return *this;
00665         }
00666 /*  ----------------------------------------------------------------------
00667     GETTERS & SETTERS
00668     ----------------------------------------------------------------------  */
00669 public:
00673     inline Text         GetAt(uint32 udx) const
00674                             { return isValidIndex(udx) ? m_str[udx] : '\0'; }
00681     inline void         SetAt(uint32 udx, Text ch)
00682                             {
00683                             if (isValidIndex(udx))
00684                                 m_str[udx] = ch;
00685                             }
00689     inline void         SetEmpty(void)
00690                             { m_str.clear(); }
00693     inline int32        GetLength(void) const
00694                             { return m_str.length(); }
00697     inline StringPtr    GetString(void) const
00698                             { return IsEmpty() ? kStrEmpty : m_str.c_str(); }
00701     inline int32        GetValue(void) const
00702                             { return IsEmpty() ? 0 : Humble::safe_strtoi( m_str.c_str() ); }
00703 /*  ----------------------------------------------------------------------
00704     INLINES
00705     ----------------------------------------------------------------------  */
00706 public:
00709     inline bool         IsEmpty(void) const 
00710                             { return m_str.empty(); }
00713     inline bool         IsNotEmpty(void) const  
00714                             { return !m_str.empty(); }
00715 protected:
00719     inline bool         isValidIndex(const uint32 udx) const
00720                             { return (std::string::size_type(udx) < m_str.length()); }
00721 /*  ----------------------------------------------------------------------
00722     OPERATORS
00723     ----------------------------------------------------------------------  */
00724 public:
00725                         operator StringPtr (void) const
00726                             { return GetString(); }
00727 //  This argument MUST be a true 'int' to avoid compiler errors
00728     Text                operator [] (int index) const
00729                             { return GetAt(index); }
00730 
00731     bool                operator == (StringPtr pstr) const
00732                             { return (m_str == pstr); }
00733     bool                operator == (const HString & rhs) const
00734                             { return (m_str == rhs.m_str); }
00735 
00736     bool                operator != (StringPtr pstr) const
00737                             { return (m_str != pstr); }
00738     bool                operator != (const HString & rhs) const
00739                             { return (m_str != rhs.m_str); }
00740 
00741     bool                operator < (StringPtr pstr) const
00742                             { return (m_str < pstr); }
00743     bool                operator < (const HString & rhs) const
00744                             { return (m_str < rhs.m_str); }
00745 
00746     bool                operator <= (StringPtr pstr) const
00747                             { return (m_str <= pstr); }
00748     bool                operator <= (const HString & rhs) const
00749                             { return (m_str <= rhs.m_str); }
00750 
00751     bool                operator > (StringPtr pstr) const
00752                             { return (m_str > pstr); }
00753     bool                operator > (const HString & rhs) const
00754                             { return (m_str > rhs.m_str); }
00755 
00756     bool                operator >= (StringPtr pstr) const
00757                             { return (m_str >= pstr); }
00758     bool                operator >= (const HString & rhs) const
00759                             { return (m_str >= rhs.m_str); }
00760                             
00761     HString &           operator = (StringPtr pstr)
00762                             {
00763                             m_str = STR_SAFE(pstr);
00764                             return *this;
00765                             }
00766 
00767     HString &           operator = (const HString & rhs)
00768                             {
00769                             if (&rhs != this)
00770                                 m_str.assign(rhs.m_str);
00771                             return *this;
00772                             }
00773 
00774     HString &           operator = (const std::string & rhs)
00775                             {
00776                             if (&rhs != &m_str)
00777                                 m_str = rhs;
00778                             return *this;
00779                             }
00780 
00781     HString &           operator += (StringPtr pstr)
00782                             { 
00783                             if (STR_VALID(pstr))
00784                                 m_str += pstr; 
00785                             return *this; 
00786                             }
00787 
00788     HString &           operator += (const HString & rhs)
00789                             { 
00790                             m_str.append(rhs.m_str);
00791                             return *this; 
00792                             }
00793 
00794     friend HString      operator + (const HString & str1, const HString & str2)
00795                             {
00796                             HString str(str1);
00797                             str += str2;
00798                             return str;
00799                             }
00800                             
00801     friend HString      operator + (const HString & str1, StringPtr pstr2)
00802                             {
00803                             HString str(str1);
00804                             str += pstr2;
00805                             return str;
00806                             }
00807                             
00808     friend HString      operator + (StringPtr pstr1, const HString & str2)
00809                             {
00810                             HString str(pstr1);
00811                             str += str2;
00812                             return str;
00813                             }
00814 
00815     };
00816 /*  ----------------------------------------------------------------------
00817     HStr class
00818     ----------------------------------------------------------------------  */
00834 template <uint32 MAX_LEN>
00835 class HStr : public HObj
00836     {
00837     typedef HObj        base_class;
00838     static StringPtr    ClassName(void) { return "HStr"; }
00839 /*  ----------------------------------------------------------------------
00840     VARIABLES
00841     ----------------------------------------------------------------------  */
00842 protected:
00843     Text                m_buffer[MAX_LEN+1];    
00844 /*  ----------------------------------------------------------------------
00845     CTOR / DTOR
00846     ----------------------------------------------------------------------  */
00847 public:
00848     HStr() 
00849         { SetEmpty(); }
00850     HStr(HStr const & T)
00851         { assign(T.m_buffer); }
00852     HStr(StringPtr pstr)
00853         { assign(pstr); }
00854     
00855     virtual             
00856     ~HStr() 
00857         { /* EMPTY DTOR */ };
00858 /*  ----------------------------------------------------------------------
00859     METHODS
00860     ----------------------------------------------------------------------  */
00861 public:
00869     HStr &
00870     Align(HString::Alignment align, uint32 uWidth, Text chPad = ' ') throw()
00871         {
00872         (void) HError::NoError();
00873 
00874         ASSERT(uWidth > 0);
00875         
00876         (void) Trim();
00877         
00878         switch (align)
00879             {
00880             case HString::ALIGN_DEFAULT:    // alignment defaults to "left"
00881             case HString::ALIGN_LEFT:
00882                 for (uint32 udx = GetLength(); udx < uWidth; ++udx)
00883                     SetAt(udx, chPad);
00884                 break;
00885 
00886             case HString::ALIGN_RIGHT:
00887                 if (uWidth > uint32(GetLength()))
00888                     {
00889                     Text    szTmp[MAX_LEN+1] = { '\0' };
00890                     
00891                     uWidth -= GetLength();  // now is count of left pad characters
00892                     for (uint32 udx = 0; udx < uWidth; ++udx)
00893                         szTmp[udx] = chPad;
00894                     
00895                     STR_NCPY(&szTmp[uWidth], m_buffer, MAX_LEN);
00896                     assign(szTmp);
00897                     }
00898                 break;
00899             
00900             case HString::ALIGN_CENTER:
00901                 if (uWidth > uint32(GetLength()))
00902                     {
00903                     Text    szTmp[MAX_LEN+1] = { '\0' };
00904                     uint32  uPadding = (uWidth - GetLength()) / 2;
00905                     
00906                     for (uint32 udx = 0; udx < uWidth; udx++)
00907                         szTmp[udx] = chPad;
00908 
00909                     MEM_COPY(&szTmp[uPadding], m_buffer, GetLength());
00910                     assign(szTmp);
00911                     }
00912                 break;
00913             
00914             default:
00915                 HError::Throw(ERR_BAD_PARAMETER, __FILE__, __LINE__);
00916             }
00917 
00918         return *this;
00919         }       
00926     ErrCode
00927     Append(StringPtr pstr)
00928         {
00929         if (validPtr(pstr)) 
00930             STR_CAT(m_buffer, pstr, MAX_LEN);
00931         return HError::NoError();
00932         }
00939     int32                   
00940     Compare(const HStr & rhs, bool bCase = true) const 
00941         { 
00942         if (&rhs == this) return 0; // we are always equal to ourself
00943 
00944         return bCase ?  Humble::safe_strcmp(m_buffer, rhs.m_buffer) : 
00945                         Humble::safe_strcmpi(m_buffer, rhs.m_buffer); 
00946         }
00953     int32                   
00954     Compare(StringPtr pstr, bool bCase = true) const 
00955         { 
00956         if (pstr == m_buffer) return 0; // we are always equal to ourself
00957 
00958         return bCase ?  Humble::safe_strcmp(m_buffer, pstr) : 
00959                         Humble::safe_strcmpi(m_buffer, pstr); 
00960         }
00972     int32
00973     Find(Text ch, uint32 uStart = 0) const 
00974         { 
00975         StringPtr   psz = NULL;
00976         
00977         if (isValidIndex(uStart))
00978             psz = Humble::safe_strchr(&m_buffer[uStart], ch);
00979 
00980         return GOOD_PTR(psz) ? int32(psz - m_buffer) : -1;
00981         }
00992     int32
00993     Find(StringPtr pstr, uint32 uStart = 0) const
00994         {
00995         int32   nOffset = -1;
00996         
00997         if (STR_VALID(pstr) && isValidIndex(uStart))
00998             {
00999             StringPtr   pstrHere = strstr(&m_buffer[uStart], pstr);
01000             nOffset = GOOD_PTR(pstrHere) ? int32(pstrHere - m_buffer) : -1;
01001             }
01002             
01003         return nOffset;
01004         }
01015     int32           
01016     FindLast(Text ch) const 
01017         {
01018         StringPtr   psz = Humble::safe_strrchr(m_buffer, ch);
01019         
01020         return GOOD_PTR(psz) ? int32(psz - m_buffer) : -1;
01021         }
01027 #ifndef DOXYGEN_SHOULD_SKIP_THIS
01028     GCC_ONLY(__attribute__((format(printf,2,3))))
01029 #endif
01030     int32
01031     Format(StringPtr pstr, ...)
01032         {
01033         int32   nLen;
01034         va_list vaList;
01035         
01036         va_start(vaList, pstr);
01037         nLen = Humble::safe_vsprintf(m_buffer, MAX_LEN, pstr, vaList);
01038         va_end(vaList);
01039 
01040         return nLen;
01041         }
01052     HStr<MAX_LEN> 
01053     Left(uint32 uCount) const
01054         {
01055         Text    szTmp[MAX_LEN+1] = { '\0' };
01056         uint32  uLen = GetLength();
01057 
01058         if (uCount >= uLen)
01059             Humble::safe_strncpy(szTmp, m_buffer, MAX_LEN);
01060         else if (uCount > 0)
01061             Humble::safe_strncpy(szTmp, m_buffer, uCount);
01062         
01063         return HStr<MAX_LEN>(szTmp);
01064         }
01069     HStr &
01070     MakeLower(void)     
01071         { 
01072         (void) Humble::safe_strlwr(m_buffer); 
01073         return *this;
01074         }
01079     HStr &
01080     MakeUpper(void)     
01081         { 
01082         (void) Humble::safe_strupr(m_buffer); 
01083         return *this;
01084         }
01096     HStr<MAX_LEN> 
01097     Mid(uint32 uStart, int32 nCount = -1) const
01098         {
01099         Text    szTmp[MAX_LEN+1] = { '\0' };
01100         uint32  uCount = (nCount < 0) ? GetLength() : nCount;
01101                 
01102         if (isValidIndex(uStart) && uCount > 0)
01103             Humble::safe_strncpy(szTmp, &m_buffer[uStart], uCount);
01104         
01105         return HStr<MAX_LEN>(szTmp);
01106         }
01117     int32
01118     Replace(Text chOld, Text chNew)
01119         {
01120         int32   nCount = 0;
01121 
01122         for (uint32 udx = 0; udx < MAX_LEN; ++udx)
01123             if (m_buffer[udx] == chOld)
01124                 {
01125                 m_buffer[udx] = chNew;
01126                 nCount++;
01127                 }
01128 
01129         return nCount;
01130         }
01141     HStr<MAX_LEN>
01142     Right(uint32 uCount) const
01143         {
01144         HStr<MAX_LEN>   str;
01145         uint32          uLen = GetLength();
01146 
01147         if (uCount >= uLen)
01148             str.assign(m_buffer);
01149         else if (uCount > 0)
01150             str.assign(&m_buffer[uLen - uCount]);
01151         
01152         return str;
01153         }
01158     HStr &
01159     Trim(void)
01160         { 
01161         TrimRight(); 
01162         TrimLeft();
01163         return *this; 
01164         }
01169     HStr &
01170     TrimLeft(void)
01171         {
01172         uint32  uFirst;
01173         
01174         for (uFirst = 0; uFirst < MAX_LEN; ++uFirst)
01175             if (!isspace(m_buffer[uFirst]))
01176                 break;
01177         
01178         if (uFirst > 0) // true if we need to shift everything down
01179             {
01180             MEM_MOVE(m_buffer, &m_buffer[uFirst], MAX_LEN - uFirst);
01181             MEM_ZERO(&m_buffer[MAX_LEN - uFirst], uFirst);
01182             }
01183             
01184         return *this;
01185         }
01190     HStr &
01191     TrimRight(void)
01192         {
01193         for (uint32 udx = GetLength() - 1; isspace(m_buffer[udx]); --udx) 
01194             {
01195             m_buffer[udx] = '\0';
01196             if (udx == 0)
01197                 break;
01198             }
01199             
01200         return *this;
01201         }
01202 protected:
01207     void                
01208     assign(StringPtr pstr)
01209         { 
01210         if (validPtr(pstr)) 
01211             STR_NCPY(m_buffer, pstr, MAX_LEN); 
01212         else 
01213         SetEmpty(); 
01214         }
01215 /*  ----------------------------------------------------------------------
01216     GETTERS / SETTERS
01217     ----------------------------------------------------------------------  */
01218 public:
01224     inline Text         GetAt(int32 index) const
01225                             { return isValidIndex(index) ? m_buffer[index] : '\0'; }
01229     inline void         SetAt(int32 index, Text ch) 
01230                             {
01231                             if (isValidIndex(index)) 
01232                                 m_buffer[index] = ch; 
01233                             }
01236     inline int32        GetLength(void) const 
01237                             { return STR_NLEN(m_buffer, MAX_LEN+1); }
01240     inline static int32 GetMaxLength(void)
01241                             { return MAX_LEN; }
01244     inline StringPtr    GetString(void) const
01245                             { return m_buffer; }                            
01248     inline int32        GetValue(void) const
01249                             { return IsEmpty() ? 0 : Humble::safe_strtoi(m_buffer); }
01251     inline void         SetEmpty(void)         
01252                             { MEM_ZERO(m_buffer, MAX_LEN+1); }
01253 /*  ----------------------------------------------------------------------
01254     INLINES
01255     ----------------------------------------------------------------------  */
01256 public:
01263     inline int32        FormatV(StringPtr pstr, va_list & vaList)
01264                             { return Humble::safe_vsprintf(m_buffer, MAX_LEN, pstr, vaList); }
01269     uint32              Hash(void) const
01270                             { return HStr::Hash(m_buffer); }
01275     inline bool     IsEmpty(void) const 
01276                             { return (m_buffer[0] == '\0'); }
01281     inline bool     IsNotEmpty(void) const 
01282                             { return (m_buffer[0] != '\0'); }
01283 protected:
01294     inline bool         isValidIndex(uint32 udx) const
01295                             { return (udx < MAX_LEN); }
01305     inline bool         validPtr(StringPtr pstr) const
01306                             { return (GOOD_PTR(pstr) && pstr != m_buffer); }
01307 
01308 /*  ----------------------------------------------------------------------
01309     OPERATORS
01310     ----------------------------------------------------------------------  */
01311 public:
01312     bool                operator == (StringPtr pstr) const
01313                             { return (Compare(pstr, true) == 0); }
01314     bool                operator != (StringPtr pstr) const 
01315                             { return (Compare(pstr, true) != 0); }
01316 
01317     bool                operator <= (StringPtr pstr) const 
01318                             { return (Compare(pstr, true) <= 0); }
01319     bool                operator <  (StringPtr pstr) const 
01320                             { return (Compare(pstr, true) <  0); }
01321     bool                operator >= (StringPtr pstr) const 
01322                             { return (Compare(pstr, true) >= 0); }
01323     bool                operator >  (StringPtr pstr) const 
01324                             { return (Compare(pstr, true) >  0); }
01325 
01326                         operator StringPtr() const
01327                             { return GetString(); }
01328 //  This argument MUST be a true 'int' to avoid compiler errors
01329     Text                operator [] (int index) const
01330                             { return GetAt(index); }
01331 
01332     HStr &              operator = (HStr const & rhs)
01333                             { assign(rhs.m_buffer); return *this; }
01334     HStr &              operator = (StringPtr pstr)
01335                             { assign(pstr); return *this;}
01336     HStr &              operator += (HStr const & rhs)
01337                             { Append(rhs.m_buffer); return *this;}
01338     HStr &              operator +=(StringPtr pstr) 
01339                             { Append(pstr); return *this;}
01340     HStr                operator + (HStr const & rhs) const
01341                             { 
01342                             HStr<MAX_LEN>   str(m_buffer);
01343                             str.Append(rhs.m_buffer);
01344                             return str; 
01345                             }
01346     HStr                operator + (StringPtr pstr) const
01347                             { 
01348                             HStr<MAX_LEN>   str(m_buffer);
01349                             str.Append(pstr);
01350                             return str;
01351                             }
01352     };
01360 typedef HStr<255>       HStrTmp;
01361 
01362 #endif  // HSTRING_H
01363 /****************************************************************************
01364 **
01365 **  $History: HString.h $
01366  * 
01367  * *****************  Version 6  *****************
01368  * User: Lee Neuse    Date: 4/17/05    Time: 12:29p
01369  * Updated in $/SkyOS.root/HFramework
01370  * Development snapshot 050417
01371  * 
01372  * *****************  Version 5  *****************
01373  * User: Neusel       Date: 2/04/05    Time: 10:45a
01374  * Updated in $/SkyOS.root/pig/Humble
01375  * 
01376  * *****************  Version 4  *****************
01377  * User: Neusel       Date: 12/23/04   Time: 1:34p
01378  * Updated in $/SkyOS.root/pig/Humble
01379  * Posted as HFramework-debug 20041223
01380  * 
01381  * *****************  Version 3  *****************
01382  * User: Neusel       Date: 12/08/04   Time: 5:06p
01383  * Updated in $/SkyOS.root/pig/Humble
01384  * 20041208
01385  * 
01386  * *****************  Version 2  *****************
01387  * User: Neusel       Date: 11/30/04   Time: 1:01p
01388  * Updated in $/SkyOS.root/pig/Humble
01389  * Released as HUMBLE_VER 20041130.
01390  * 
01391  * *****************  Version 1  *****************
01392  * User: Neusel       Date: 11/23/04   Time: 8:24a
01393  * Created in $/SkyOS.root/pig/Humble
01394 **
01395 **  -------------------------------------------------------------------------
01396 **
01397 **  End of HString.h
01398 **
01399 ****************************************************************************/
01400