Main Page   Namespace List   Class Hierarchy   Compound List   File List   Namespace Members   Compound Members   File Members  

mstring.cc

Go to the documentation of this file.
00001 
00025 #include <ctype.h>
00026 #include <stdio.h>
00027 
00028 #ifdef SunOS
00029 #include <sys/varargs.h>
00030 #else
00031 #include <stdarg.h>
00032 #endif
00033 
00034 #include "magic/mobject.h"
00035 #include "magic/mstring.h"
00036 #include "magic/mclass.h"
00037 #include "magic/mregexp.h"
00038 #include "magic/mstream.h"
00039 #include "magic/mtextstream.h"
00040 #include "magic/mdatastream.h"
00041 #include "magic/mexception.h"
00042 
00043 BEGIN_NAMESPACE (MagiC);
00044 
00045 impl_dynamic (String, {Comparable});
00046     
00047 
00049 //                         ----         o                                    //
00050 //                        (      |          _                                //
00051 //                         ---  -+- |/\ | |/ \   ___                         //
00052 //                            )  |  |   | |   | (   \                        //
00053 //                        ___/    \ |   | |   |  ---/                        //
00054 //                                               __/                         //
00056 
00057 MagiC::String::String () {
00058     mLen    = 0;
00059     mMaxLen = 0;
00060     mData   = NULL;
00061     mChkSum = 0;
00062 }
00063 
00065 MagiC::String::String (const String& orig   )
00066 {
00067     if (&orig == NULL || orig.mData==NULL) {
00068         mLen = 0;
00069         mMaxLen = 0;
00070         mData = NULL;
00071         return;
00072     }
00073     mLen = orig.mLen;
00074     mMaxLen = orig.mMaxLen;
00075     mData = new char [mMaxLen+1];
00076     memcpy (mData, orig.mData, mMaxLen+1);
00077     mChkSum = 0;
00078 }
00079 
00081 MagiC::String::String (const char* chrp      )
00082 {
00083     if (chrp) {
00084         mLen    = strlen (chrp);
00085         mMaxLen = mLen;
00086         mData   = new char [mMaxLen+1];
00087         memcpy (mData, chrp, mLen+1);
00088     } else {
00089         mLen = mMaxLen = 0;
00090         mData = NULL;
00091     }
00092     mChkSum = 0;
00093 }
00094 
00096 MagiC::String::String (char* str,            
00097                        enum strcrflags flags )
00098 {
00099     if (flags & STRCRFL_OWN)
00100         mData = str;
00101     else if (str)
00102         mData = strdup (str); // TODO
00103     else
00104         mData = NULL;
00105 
00106     mLen = mMaxLen = str? strlen (str) : 0;
00107     mChkSum = 0;
00108 }
00109 
00111 MagiC::String::String (const char* chrp,    
00112                        int n                )
00113 {
00114     if (chrp && n) {
00115         mLen    = n;
00116         mMaxLen = mLen;
00117         mData   = new char [mMaxLen+1];
00118         memcpy (mData, chrp, mLen);
00119         mData [mMaxLen] = 0x00;
00120     } else {
00121         mLen = mMaxLen = 0;
00122         mData = NULL;
00123     }
00124     mChkSum = 0;
00125 }
00126 
00128 MagiC::String::String (char* str,           
00129                        uint maxLen,         
00130                        bool own             )
00131 {
00132     if (own)
00133         mData = str;
00134     else
00135         mData = strdup (str); // TODO
00136 
00137     mData[maxLen]   = '\0';
00138     mLen            = str? strlen (str) : 0;
00139     mMaxLen         = maxLen;
00140     mChkSum         = 0;
00141 }
00142 
00143 MagiC::String::~String () {
00144     delete mData;
00145     IFDEBUG (mData = (char*) 0xdddddddd);
00146 }
00147 
00148 template<class TYPE>
00149 inline char* intToString(TYPE value, uint base) {
00150     const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
00151     if (base > sizeof(digits))
00152         throw Exception (strformat ("Too large base %d for integer-to-String conversion", base));
00153     
00154     const int   maxintlen = 40;
00155     char        buf[maxintlen];
00156     char*       loc = buf + (maxintlen-1);
00157     *(loc--) = '\x00'; // Terminate
00158 
00159     bool isNeg = false; // Remember negative sign
00160     if (value < 0) {
00161         isNeg = true;
00162         value = -value;
00163     }
00164 
00165     do {
00166         *(loc--) = digits [value % base];
00167         value /= base;
00168     } while (value);
00169 
00170     if (isNeg) // Add sign if negative
00171         *(loc--) = '-';
00172 
00173     return strdup (loc+1);
00174 }
00175 
00177 MagiC::String::String (int i, int base) {
00178     mData = intToString<int> (i, base);
00179     mLen = mMaxLen = strlen(mData);
00180     mChkSum = 0;
00181 }
00182 
00184 MagiC::String::String (uint i, int base) {
00185     mData = intToString<uint> (i, base);
00186     mLen = mMaxLen = strlen(mData);
00187     mChkSum = 0;
00188 }
00189 
00191 MagiC::String::String (long i, int base) {
00192     mData = intToString<long> (i, base);
00193     mLen = mMaxLen = strlen(mData);
00194     mChkSum = 0;
00195 }
00196 
00197 template <class TYPE>
00198 inline char* formatFloat(TYPE f, char fmt, int prec)
00199 {
00200     // Create formatting string
00201     char formatBuf [20];
00202     if (prec >= 0)
00203         sprintf (formatBuf, "%%.%d%c", prec, fmt);
00204     else
00205         sprintf (formatBuf, "%%%c", fmt);
00206 
00207     // Create actual string with the created format
00208     char buf [80+prec]; // Add prec, because it could be "high".
00209     sprintf (buf, formatBuf, f);
00210 
00211     return strdup (buf); // TODO: Use safedup
00212 }
00213 
00215 MagiC::String::String (float f,     
00216                        char fmt,    
00217                        int prec     )
00218 {
00219     mData = formatFloat<float> (f, fmt, prec);
00220     mLen = mMaxLen = strlen(mData);
00221     mChkSum = 0;
00222 }
00223 
00225 MagiC::String::String (double f,    
00226                        char fmt,    
00227                        int prec     )
00228 {
00229     mData = formatFloat<double> (f, fmt, prec);
00230     mLen = mMaxLen = strlen(mData);
00231     mChkSum = 0;
00232 }
00233 
00235 String& MagiC::String::assign (char c)
00236 {
00237     if (!mData)
00238         mData = new char [2];
00239     mData[0] = c;
00240     mData[1] = '\x00';
00241     mLen = 1;
00242     mChkSum = 0;
00243     return *this;
00244 }
00245 
00251 String& MagiC::String::append (char c)
00252 {
00253     // Ensure that our buffer is large enough
00254     ensure_spontane (mLen + 1);
00255 
00256     mData[mLen++]   = c;
00257     mData[mLen]     = '\x00'; // Terminate properly with \0
00258     mChkSum         = 0;
00259 
00260     return *this;
00261 }
00262 
00269 String& MagiC::String::append (const char* str, 
00270                                uint strlength   )
00271 {
00272     // Ensure that the string to append is not empty
00273     if (!str || strlength==0)
00274         return *this;
00275     
00276     // Ensure that our buffer is large enough
00277     if (mLen + int(strlength) > mMaxLen)
00278         ensure (mLen + strlength + 1);
00279 
00280     // Copy, but without a trailing \0
00281     memcpy (mData+mLen, str, strlength);
00282 
00283     mLen        += strlength;
00284     mData[mLen] =  '\x00'; // Terminate properly with \0
00285     mChkSum     =  0;
00286 
00287     return *this;
00288 }
00289 
00300 String& MagiC::String::replace (uint position,          
00301                                 const char* buffer,     
00302                                 int buflen              )
00303 {
00304     if (!buffer)
00305         return *this;
00306     
00307     if (buflen < 0)
00308         buflen = strlen (buffer);
00309 
00310     if ((int) position >= mLen)
00311         position = mLen;
00312 
00313     ensure_spontane (position + buflen);
00314 
00315     // Replace
00316     memcpy (mData+position, buffer, buflen);
00317 
00318     if ((int) (position + buflen) > mLen) {
00319         mLen = position + buflen;
00320         mData[mLen] = '\x00';
00321     }
00322 
00323     return *this;
00324 }
00325 
00326 
00331 String& MagiC::String::operator= (const String& other )
00332 {
00333     if (&other == NULL || other.mData==NULL || other.mLen==0) {
00334         // The string was null
00335         if (mData) {
00336             mLen    = 0;
00337             *mData  = '\x00'; // Preserve it
00338         }
00339     } else {
00340         // The string contains something
00341         mLen = other.mLen;
00342         if (mLen > mMaxLen) { // Reallocate only if necessary
00343             if (mData)
00344                 delete mData;
00345             mMaxLen = mLen;
00346             mData = new char [mMaxLen+1];
00347         }
00348         memcpy (mData, other.mData, mLen+1);
00349     }
00350     mChkSum = other.mChkSum;
00351     return *this;
00352 }
00353 
00358 String& MagiC::String::operator= (const char* chrp  )
00359 {
00360     if (!chrp || !*chrp) {
00361         // The string was null or empty
00362         if (mData) {
00363             mLen    = 0;
00364             *mData  = '\x00'; // Preserve it
00365         }
00366     } else {
00367         // The string has something
00368         mLen = strlen (chrp);
00369         if (mLen > mMaxLen) { // Reallocate only if necessary
00370             if (mData)
00371                 delete mData;
00372             mMaxLen = mLen;
00373             mData = new char [mMaxLen+1];
00374         }
00375         memcpy (mData, chrp, mLen+1);
00376     }
00377     mChkSum = 0;
00378     return *this;
00379 }
00380 
00381 /*
00382 ostream& MagiC::String::dump (ostream& out) const {
00383     out << format ("String #0x%x\n");
00384     out << "mData=" << mData << "\n";
00385     out << "mLen=" << mLen << "\n";
00386     out << "mMaxLen=" << mMaxLen << "\n";
00387     return out;
00388 }
00389 */
00390 
00399 ostream& MagiC::String::operator>> (ostream& out) const
00400 {
00401     if (mData)
00402         out << mData;
00403     else
00404         out << "(null)";
00405     return out;
00406 }
00407 
00408 /******************************************************************************/
00417 TextOStream& MagiC::String::operator>> (TextOStream& out) const
00418 {
00419     if (mData)
00420         out << mData;
00421     else
00422         out << "(null)";
00423     return out;
00424 }
00425 
00433 TextIStream& MagiC::String::operator<< (TextIStream& is)
00434 {
00435     ensure_spontane (80);
00436     mLen        = 0;
00437     mData[0]    = '\x00';
00438 
00439     int w = is.width (0);
00440     IODevice *dev = is.device (); // Read the device directly
00441     while (1) {
00442         // Read one character.
00443         int ch = dev->getch();
00444 
00445         //printf ("[%c]", ch);
00446 
00447         // Terminate string on either EOF or whitespace.
00448         if (ch == EOF)
00449             break;
00450         else if (isspace (ch))
00451             break;
00452 
00453         (*this) += ch;
00454         if (--w == 1)
00455             break;
00456     }
00457 
00458     if (mLen == 0) {
00459         // Didn't read anything. This is a problem. NOTE: REALLY????? Uh...
00460         //dev->setStatus (IO_ReadError);
00461     }
00462 
00463     return is;
00464 }
00465 
00466 /******************************************************************************/
00469 DataOStream& MagiC::String::operator>> (DataOStream& arc) const
00470 {
00471     arc.name ("mLen") << mLen;
00472     arc.name ("mMaxLen") << mMaxLen;
00473     arc.name ("mData").writeRawBytes (mData, mLen? mLen+1 : 0);
00474     return arc;
00475 }
00476 
00477 /******************************************************************************/
00480 DataIStream& MagiC::String::operator<< (DataIStream& arc)
00481 {
00482     arc >> mLen;
00483     arc >> mMaxLen;
00484 
00485     ensure (mMaxLen);
00486     arc.readRawBytes (mData, mLen+1);
00487     mData[mLen] = '\x00';
00488     mChkSum=0;
00489     
00490     return arc;
00491 }
00492 
00493 /******************************************************************************/
00496 String MagiC::String::operator+ (const String& other) const
00497 {
00498     String result = *this;
00499     result += other;
00500     return result;
00501 }
00502 
00503 /******************************************************************************/
00506 String MagiC::String::operator+ (const char* str ) const
00507 {
00508     String result = *this;
00509     result += String(str);
00510     return result;
00511 }
00512 
00513 /******************************************************************************/
00517 bool findLowestNum (const String& str, uint& start, uint& end)
00518 {
00519     // Scan the string using a state machine.
00520     enum states {NORMAL=0, FOUNDPERCENT};
00521     int state = NORMAL;     // Current state
00522     int number = 0;         // Number currently being scanned
00523     int curPos = 0;         // Starting position of the currently scanned number
00524     int lowest = 999999;    // Lowest number found so far
00525     start = 0;              // Start position of the lowest number found so far
00526     end = 0;                // End position of the lowest number found so far
00527 
00528     for (uint i=0; i<str.length(); i++) {
00529         switch (state) {
00530           case NORMAL:
00531               if (str[i] == '%') {
00532                   state = FOUNDPERCENT;
00533                   number = 0;
00534                   curPos = i;
00535               }
00536               break;
00537           case FOUNDPERCENT:
00538               if (isdigit(str[i]))
00539                   number = number*10 + int(str[i]-'0');
00540               else {
00541                   if (number < lowest) {
00542                       // Found a new lowest
00543                       lowest    = number;
00544                       start     = curPos;
00545                       end       = i;
00546                   }
00547                   state = NORMAL;
00548               }
00549               break;
00550         }
00551     }
00552     if (state == FOUNDPERCENT && number < lowest) {
00553         // Found a new lowest in the end of the string
00554         start   = curPos;
00555         end     = str.length();
00556         lowest  = 0;
00557     }
00558 
00559     return (lowest!=999999);
00560 }
00561 
00562 /******************************************************************************/
00565 String MagiC::String::arg (const String& replacement, int fieldwidth) const {
00566     uint start, end;
00567     if (findLowestNum (*this, start, end)) {
00568         int     realwidth   = (replacement.length() > (uint)fieldwidth)? replacement.length() : fieldwidth;
00569         int     maxLen      = start + realwidth + (length()-end);
00570         char*   buf         = new char[maxLen + 1];
00571         char*   resultPos   = buf;
00572 
00573         // Concatenate beginning of the string, if not in the beginning
00574         if (start > 0) {
00575             memcpy (resultPos, mData, start);
00576             resultPos += start;
00577         }
00578 
00579         // Concatenate replacement (with padding)
00580         if (realwidth > 0) {
00581             for (int padding = (realwidth>fieldwidth)? 0 : fieldwidth-replacement.length(); padding>0; padding--)
00582                 *(resultPos++) = ' ';
00583             memcpy (resultPos, replacement.mData, replacement.length());
00584             resultPos += replacement.length();
00585         }
00586 
00587         // Concatenate rest of the string, if not at end
00588         if (end < (uint) mLen) {
00589             memcpy (resultPos, mData+end, mLen-end);
00590             resultPos += mLen-end;
00591         }
00592         *resultPos = '\x00';
00593 
00594         // Create return object using the buffer.
00595         return String (buf, maxLen, true);
00596     } else
00597         // This is an error situation, basicly, but we return something nevertheless.
00598         return *this;
00599 }
00600 
00611 /******************************************************************************/
00614 String& MagiC::String::dellast (uint n)
00615 {
00616     if (!mData)
00617         return *this;
00618 
00619     // Delete at most the length of the string
00620     if (n >= (uint) mLen)
00621         n = mLen;
00622     mLen -= n;
00623     mData[mLen] = 0;
00624     mChkSum = 0;
00625     return *this;
00626 }
00627 
00629 void MagiC::String::chop ()
00630 {
00631     while (mLen>0 && isspace(mData[mLen-1]))
00632         dellast (1);
00633     mChkSum=0;
00634 }
00635 
00642 int MagiC::String::fast_isequal (const String& other) const {
00643     if (other.mChkSum == mChkSum)
00644         return operator== (other.mData);
00645     else
00646         return 0;
00647 }
00648 
00655 String& MagiC::String::hexcode (const String& other) {
00656     const char hexcodes[] = "0123456789abcdef";
00657     int otherlen = other.length();
00658     ensure (otherlen*2);
00659     for (int i=0; i<otherlen; i++) {
00660         *this += hexcodes [((unsigned int) other.mData[i])/16];
00661         *this += hexcodes [((unsigned int) other.mData[i])%16];
00662     }
00663     mChkSum=0;
00664     return *this;
00665 }
00666 
00673 void MagiC::String::quote (char quotechar, int flags) {
00674     FORBIDDEN; // Not implemented
00675 }
00676 
00684 void MagiC::String::unquote (char quotechar, int flags) {
00685     enum    states {Waiting, GotEqual, GotFirst, GotSoftLinebreak};
00686 
00687     String  hextable    = "0123456789ABCDEF";
00688     int     state       = Waiting;
00689     int     value       = 0;
00690     String  tmp;                             // Storage for characters after translation
00691 
00692     tmp.reserve (mLen);
00693 
00694     // Loop through string
00695     for (uint i=0 ; i < (uint) mLen ; i++) {
00696         char c = (*this)[i];
00697         switch (state) {
00698             case Waiting:
00699                 if (c == quotechar)
00700                     state=GotEqual;
00701                 else
00702                     if (c=='+' && (flags&QUOTE_HTML))
00703                         tmp += ' ';
00704                     else
00705                         tmp += c;
00706                 break;
00707                 
00708             case GotEqual:
00709                 if ((value=hextable.find(c)) != -1) {
00710                     state=GotFirst;
00711                     value*=16; // Shiftataan ylöspäin....
00712                 } else { // Hmm, ei ollutkaan heksaluku...
00713                     if (c=='\r') { // soft CRLF
00714                         state = GotSoftLinebreak;
00715                     } else {
00716                         // Something weird...
00717                         // Error in Q-P code! Let's recover it...
00718                         state = Waiting;
00719                         tmp += quotechar; 
00720                         tmp += c;
00721                     }
00722                 }
00723                 break;
00724                 
00725             case GotFirst:
00726                 if (hextable.find(c) != -1) {
00727                     value+=hextable.find (c);
00728                     tmp += char(value);
00729                     state=Waiting; // Ok, palataan normaaliin tilaan...
00730                 } else {
00731                     // Jotain omituista, virhe QP-koodista.. yritetään toipua..
00732                     tmp += quotechar;
00733                     tmp += char(value);
00734                     tmp += c;
00735                     state = Waiting; // Så vi ventar igen..
00736                 }
00737                 break;
00738                 
00739             case GotSoftLinebreak:
00740                 // Not a soft linebreak after all?
00741                 if (c!='\n')
00742                     // Try to recover somehow...
00743                     tmp += c;
00744                 state=Waiting;
00745                 break;
00746         };
00747     }
00748 
00749     if (state!= Waiting) {
00750         // Hmm, siellä oli siis lopussa yksinäinen '=' -> PANIC!
00751         tmp += '=';
00752         if (state==GotFirst)
00753             // DOUBLEPANIC!, mutta varaudutaan silti...
00754             // Hmm, tätä ei pitäisi tarvita tehdä...
00755             tmp += char(hextable[uint(state/16)]);
00756     } // DON'T PANIC!
00757 
00758     // Laitetaan loppunulli
00759     // tmp += '\x00';
00760     // tmp.mLen = respos;
00761 
00762     (*this) = tmp;
00763 }
00764 
00766 String MagiC::String::mid (uint from, int n) const {
00767     String result;
00768     
00769     // Jos pituus on -1, otetaan loput merkkijonosta
00770     if (n==-1)
00771         n = mLen-from;
00772 
00773     // Jos pyydetään merkkijonon ulkopuolelta tai tyhjä jono
00774     if (from >= (uint) mLen || mLen==0)
00775         return "";
00776 
00777     // Jos pyyntö menee merkkijonon ulkopuolelle, pienennetään pyyntöä
00778     if (((from + n) > (uint) mLen))
00779         n = mLen-from;
00780 
00781     ASSERT (mMaxLen>=n);
00782     
00783     // Luodaan uusi merkkijono
00784     result.mLen = n;
00785     result.mMaxLen = mMaxLen;
00786     result.mData = new char [mMaxLen+1];
00787     strncpy (result.mData, mData+from, n);
00788     result.mData [n] = 0;
00789 
00790     return result;
00791 }
00792 
00794 String MagiC::String::left (uint n) const {
00795     return mid (0, n);
00796 }
00797 
00799 String MagiC::String::right (uint n) const {
00800     String result;
00801     
00802     if (n < (uint) mLen)
00803         result = mid (mLen-n);
00804     else
00805         result = *this;
00806 
00807     return result;
00808 }
00809 
00814 int MagiC::String::find (const String& subs, uint n) const {
00815     for (int i=n; i <= (mLen-subs.mLen); i++)
00816         if (!strncmp (mData+i, subs.mData, subs.mLen))
00817             return i;
00818     return -1;
00819 }
00820 
00825 int MagiC::String::find (const char c, uint n) const {
00826     char* pos = (char*) memchr (mData+n, c, mLen);
00827     return pos? pos-mData : -1;
00828 }
00829 
00837 int MagiC::String::findRev (const String& subs, int n) const {
00838     if (n<0)
00839         n += mLen;
00840     for (int i=n; i>=0; i--)
00841         if (!strncmp (mData+i, subs.mData, subs.mLen))
00842             return i;
00843     return -1;
00844 }
00845 
00846 String* MagiC::String::clone () const {
00847     return new String (*this);
00848 }
00849 
00851 int MagiC::String::operator== (const char* other) const {
00852     if (!this)
00853         return 0;
00854     if (mData && other)
00855         return (!strcmp (mData, other));
00856     if ((!mData) && (!other))
00857         return 1;
00858     return 0;
00859 }
00860 
00865 int MagiC::String::operator== (const Comparable& other) const {
00866     if (getclass().issameclass (other))
00867         return operator== ((const String&) other);
00868     else
00869         return 0;
00870 }
00871 
00875 void MagiC::String::reserve (int amount) {
00876     if (mData) {
00877         char* newmData = new char [amount+1];
00878         if (!newmData)
00879             throw runtime_error ("Out of memory or something in MagiC::String::reserve()");
00880         memcpy (newmData, mData, mLen+1);
00881         delete mData;
00882         mData = newmData;
00883         mData [amount] = 0x00;
00884     } else {
00885         mData = new char[amount+1];
00886         if (!mData)
00887             throw runtime_error ("Out of memory or something in MagiC::String::reserve()");
00888         *mData = 0x00;
00889     }
00890     mMaxLen = amount;
00891 }
00892 
00910 /*
00911 const char& MagiC::String::operator[] (uint n) const {
00912     if (n<mLen)
00913         return mData [n];
00914     else
00915         throw Exception ("String index out of bounds");
00916 }
00917 */
00918 
00920 /*
00921 char& MagiC::String::operator[] (uint n) {
00922     if (n<mLen)
00923         return mData [n];
00924     else {
00925         throw Exception ("String index out of bounds");
00926         return *mData; // To get rid of a warning
00927     }
00928 }
00929 */
00930 
00934 void MagiC::String::split (Array<String>& trg, const char delim) const {
00935     if (!this || !mLen)
00936         return;
00937 
00938     // Use temporary copy
00939     char* tmp = new char [mLen+1];
00940     memcpy (tmp, mData, mLen+1);
00941     tmp[mLen]=0;
00942 
00943     // Change delimiters to null-characters
00944     for (int i=0; i<mLen; i++)
00945         if (tmp[i]==delim)
00946             tmp[i]=0;
00947 
00948     // Create response
00949     trg.empty ();
00950     for (int pos = 0, i=0; pos<mLen; pos+=strlen (tmp+pos)+1, i++) {
00951         String tmps = tmp+pos;
00952         trg.put (tmps, i);
00953     }
00954     delete tmp;
00955 }
00956 
00960 void MagiC::String::join (const Array<String>& src, const char delim) {
00961     // Lasketaan kohdemerkkijonon pituus tilanvarausta varten
00962     int newlen = src.size() - 1;
00963     for (int i=0; i<src.size(); i++)
00964         newlen += src[i].length();
00965 
00966     // Varataan tila
00967     reserve (newlen);
00968     *this = "";
00969 
00970     // Katenoidaan merkkijonot
00971     for (int i=0; i < src.size(); i++) 
00972         if (!src[i].isEmpty ()) {
00973             *this += src[i];
00974             if (i < src.size() - 1)
00975                 *this += delim;
00976         }
00977 
00978     mChkSum=0;
00979 }
00980 
00984 String MagiC::String::stripWhiteSpace () const {
00985     uint s=0, e=mLen;
00986     while (s < (uint) mLen && strchr (" \t\r\n",(*this)[s])) // TODO: Add ff, vt
00987         s++;
00988     while (e>s && strchr (" \t\r\n",(*this)[e-1])) // TODO: Add ff, vt
00989         e--;
00990     return mid (s, e-s);
00991 }
00992 
00997 String MagiC::String::simplifyWhiteSpace () const {
00998     if (mLen == 0)
00999         return String();
01000 
01001     char*   buffer  = new char[mLen+1]; // Add 1 for terminating \x00
01002     char*   trgPos  = buffer;
01003     int     pos     = 0;
01004 
01005     // Strip whitespace from beginning
01006     for (pos=0; pos<mLen; pos++)
01007         if (!isspace(mData[pos]))
01008             break;
01009 
01010     // Strip duplicate whitespaces
01011     bool oneWhitespace=false;
01012     for (; pos<mLen; pos++) {
01013         if (isspace(mData[pos])) {
01014             if (!oneWhitespace)
01015                 *(trgPos++) = mData[pos];
01016             oneWhitespace = true;
01017         } else {
01018             *(trgPos++) = mData[pos];
01019             oneWhitespace = false;
01020         }
01021     }
01022 
01023     // Strip whitespace from end (there can be only one)
01024     if (isspace (*(trgPos-1)))
01025         trgPos--;
01026     *trgPos = '\x00';
01027 
01028     if (trgPos > buffer)
01029         // Construct using the buffer.
01030         return String (buffer, mLen+1, true);
01031     else {
01032         // The string became empty -> return really empty string.
01033         delete buffer;
01034         return String ();
01035     }
01036 }
01037 
01038 void MagiC::String::upper() const {
01039     for (int i=0; i<mLen; i++)
01040         mData[i] = toupper (mData[i]);
01041 }
01042 
01043 void MagiC::String::lower() const {
01044     for (int i=0; i<mLen; i++)
01045         mData[i] = tolower (mData[i]);
01046 }
01047 
01053 int MagiC::String::regmatch (const char* expr) const {
01054     if (!mData)
01055         return 0;
01056     RegExp rexp (expr);
01057     return rexp.match (mData);
01058 }
01059 
01070 int MagiC::String::regmatch (const char* expr, Array<String>& target) const {
01071     if (!mData)
01072         return 0;
01073     RegExp rexp (expr);
01074     return rexp.match (*this, target);
01075 }
01076 
01079 int MagiC::String::regmatch (RegExp& compiled, Array<String>& target) const {
01080     if (!mData)
01081         return 0;
01082     return compiled.match (*this, target);
01083 }
01084 
01101 void MagiC::String::empty ()
01102 {
01103     if (mData) {
01104         mLen = 0;
01105         mData[mLen] = '\x00';
01106     }
01107 }
01108 
01111 char MagiC::String::checksum () {
01112     mChkSum = 0;
01113     hashfunc (256);
01114     return mChkSum;
01115 }
01116 
01130 int MagiC::String::hashfunc (int hashsize) const
01131 {
01132     ASSERTWITH (hashsize<=256, format ("String hash size maximum is 256 slots",
01133                                        " (hashsize was %d)", hashsize));
01134     
01135     // Jos on checksum laskettu, palautetaan sen mukainen arvo
01136     if (mChkSum)
01137         return mChkSum % hashsize;
01138 
01139     if (!mLen)
01140         return 0;
01141 
01142     int sum = 0;
01143     if (mLen < 10) {
01144         // Lyhyille merkkijonoille
01145         
01146         for (int i=0; i<mLen; i++)
01147             sum += mData[i];
01148 
01149         (unsigned char&) mChkSum = sum % 256;
01150     } else {
01151         // Pitemmille merkkijonoille
01152 
01153         // Sum of the first, middle and last character
01154         sum = int(mData[0]) + int(mData[mLen/2]) + mLen*int(mData[mLen-1]);
01155 
01156         (unsigned char&) mChkSum = sum % 256;
01157     }
01158 
01159     // TRACE4 ("%s -> %d/%d/%d", mData, sum, int(mChkSum), int(mChkSum%hashsize));
01160     return mChkSum % hashsize;
01161 }
01162 
01168 /*
01169 MagiC::String::operator float () const {
01170     if (mData) {
01171         char* tmp = strdup (mData);
01172         for (char* tmp_p=tmp; *tmp_p; tmp_p++)
01173             if (*tmp_p == ',')
01174                 *tmp_p = '.';
01175         float res = atof (tmp);
01176         free (tmp);
01177         return res;
01178     }
01179     return 0;
01180 }
01181 */
01182 
01183 
01185 //                                     |                              o                  //
01186 //  ___       |   ___        _    ___  |     __         _    ___   |           _    ____ //
01187 // /   ) \ / -+- /   ) |/\ |/ \   ___| |    /   |   | |/ \  |   \ -+- |  __  |/ \  (     //
01188 // |---   X   |  |---  |   |   | (   | |    +-- |   | |   | |      |  | /  \ |   |  \__  //
01189 //  \__  / \   \  \__  |   |   |  \__| |    |    \__! |   |  \__/   \ | \__/ |   | ____) //
01190 //                                          |                                            //
01192 
01194 const String MagiC::emptystring;
01195 
01205 char* MagiC::strnchr (const char* str, int mLen, char c) {
01206     const char* pos=str;
01207     for (int i=0; i<mLen; i++, pos++)
01208         if (*pos == c)
01209             return (char*) pos;
01210     return NULL;
01211 }
01212 
01221 char* safedup (const char* orig, int maxlen) {
01222     if (orig) {
01223         // Duplicate.
01224         // We can't use strdup, because ANSI C++ doesn't have it.
01225         int len = strlen (orig)+1; // Length with end-null.
01226         char* result = new char [len];
01227         memcpy (result, orig, len);
01228         return result;
01229     } else
01230         return (char*) NULL;
01231 }
01232 
01237 int MagiC::fgetS (FILE* in, String& str) {
01238     char    cbuff [4097],
01239             *nlpos;
01240     int bytesread = 0;
01241     str = "";
01242 
01243     do {
01244         // Read a data block to buffer
01245         char* callResult = fgets (cbuff, 4096, in);
01246 
01247         if (callResult == NULL)
01248             break;
01249 
01250         // See if the block contains a newline
01251         nlpos = strnchr (cbuff, 4096, '\n');
01252 
01253         // Calculate the length of the block read
01254         int blocklength = nlpos? nlpos-cbuff+1 : 4096;
01255 
01256         // Add to result
01257         str.append (cbuff, blocklength);
01258 
01259         bytesread += blocklength;
01260 
01261         // Toistetaan kunnes löydetään lohkosta rivinvaihto
01262     } while (!nlpos && !feof (in));
01263 
01264     return bytesread;
01265 }
01266 
01271 istream& MagiC::getS    (istream& is, String& str, char term) {
01272     str = ""; // TODO: This may shorten the maxlen?
01273     str.ensure_spontane (80);
01274     
01275     register streambuf *sb = is.rdbuf ();
01276     bool eof=false;
01277     while (true) {
01278         int ch = sb->sbumpc ();
01279         if (ch == EOF) {
01280             eof = true;
01281             is.setstate (ios::eofbit);
01282             break;
01283 
01284             // Separation with given character, or whitespace, if
01285             // the terminator is \xff.
01286         } else if ((term!='\xff' && ch==term) || (term=='\xff' && isspace (ch)))
01287             break;
01288         
01289         // Skip CR
01290         else if (term!='\n' || ch!='\r')
01291             str += char(ch);
01292     }
01293 
01294     if (eof && str.length()==0)
01295         is.setstate (ios::failbit);
01296 
01297     return is;
01298 }
01299 
01300 void nullcharspace (int charspace [256]) {
01301     for (int i=0; i<256; i++)
01302         charspace [i]=0;
01303 }
01304 
01306 void MagiC::loadString (String& str, const String& filename) {
01307     FILE* in = fopen (filename, "rb");
01308     if (!in)
01309         return;
01310     str = "";
01311     String buff;
01312     buff.reserve (200);
01313     while (!feof(in)) {
01314         fgetS (in, buff);
01315         str += buff;
01316     }
01317     fclose (in);
01318 }
01319 
01320 /*****************************************************************************/
01323 String MagiC::strformat (const char* sformat, 
01324                          ...)                 
01325 {
01326     va_list args;
01327     va_start (args, sformat);
01328 
01329     String result = vstrformat (sformat, args);
01330     
01331     va_end (args);
01332     
01333     return result;
01334 }
01335 
01336 /*****************************************************************************/
01339 String MagiC::vstrformat (const char* sformat, 
01340                           va_list ap)          
01341 {
01342     // Reserve a smallish buffer
01343     char* buffer = new char [STRFORMAT_SMALL_BUFFER_SIZE + 1];
01344 
01345     // Try writing to a smallish buffer
01346     int written = vsnprintf (buffer, STRFORMAT_SMALL_BUFFER_SIZE + 1, sformat, ap);
01347 
01348     if (written > STRFORMAT_SMALL_BUFFER_SIZE) {
01349         // Grow the buffer to the required size
01350         delete buffer;
01351         buffer = new char [written+1];
01352 
01353         // Reprint to the larger buffer
01354         vsnprintf (buffer, written+1, sformat, ap);
01355     }
01356 
01357     return String (buffer, String::STRCRFL_OWN);
01358 }
01359 
01360 END_NAMESPACE;
01361 

Generated on Thu Feb 10 20:06:42 2005 for LibMagiC by doxygen1.2.18