Main Page   Class Hierarchy   Compound List   File List   Compound Members  

mstring.cc

00001 /***************************************************************************
00002  *   This file is part of the MagiC++ library.                             *
00003  *                                                                         *
00004  *   Copyright (C) 1998-2001 Marko Grönroos <magi@iki.fi>                  *
00005  *                                                                         *
00006  ***************************************************************************
00007  *                                                                         *
00008  *  This library is free software; you can redistribute it and/or          *
00009  *  modify it under the terms of the GNU Library General Public            *
00010  *  License as published by the Free Software Foundation; either           *
00011  *  version 2 of the License, or (at your option) any later version.       *
00012  *                                                                         *
00013  *  This library is distributed in the hope that it will be useful,        *
00014  *  but WITHOUT ANY WARRANTY; without even the implied warranty of         *
00015  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU      *
00016  *  Library General Public License for more details.                       *
00017  *                                                                         *
00018  *  You should have received a copy of the GNU Library General Public      *
00019  *  License along with this library; see the file COPYING.LIB.  If         *
00020  *  not, write to the Free Software Foundation, Inc., 59 Temple Place      *
00021  *  - Suite 330, Boston, MA 02111-1307, USA.                               *
00022  *                                                                         *
00023  ***************************************************************************/
00024 
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 
00039 
00040 impl_dynamic (String, {Comparable});
00041     
00042 
00044 //                         ----         o                                    //
00045 //                        (      |          _                                //
00046 //                         ---  -+- |/\ | |/ \   ___                         //
00047 //                            )  |  |   | |   | (   \                        //
00048 //                        ___/    \ |   | |   |  ---/                        //
00049 //                                               __/                         //
00051 
00052 MagiC::String::String () {
00053     mLen    = 0;
00054     mMaxLen = 0;
00055     mData   = NULL;
00056     mChkSum = 0;
00057 }
00058 
00060 MagiC::String::String (const String& orig) {
00061     if (&orig == NULL || orig.mData==NULL) {
00062         mLen = 0;
00063         mMaxLen = 0;
00064         mData = NULL;
00065         return;
00066     }
00067     mLen = orig.mLen;
00068     mMaxLen = orig.mMaxLen;
00069     mData = new char [mMaxLen+1];
00070     memcpy (mData, orig.mData, mMaxLen+1);
00071     mChkSum = 0;
00072 }
00073 
00075 MagiC::String::String (const char* chrp) {
00076     if (chrp) {
00077         mLen    = strlen (chrp);
00078         mMaxLen = mLen;
00079         mData   = new char [mMaxLen+1];
00080         memcpy (mData, chrp, mLen+1);
00081     } else {
00082         mLen = mMaxLen = 0;
00083         mData = NULL;
00084     }
00085     mChkSum = 0;
00086 }
00087 
00093 MagiC::String::String (char* str, bool own) {
00094     mData = str;
00095     mLen = mMaxLen = str? strlen (str) : 0;
00096     mChkSum = 0;
00097 }
00098 
00101 MagiC::String::String (const char* chrp, int n) {
00102     if (chrp && n) {
00103         mLen    = n;
00104         mMaxLen = mLen;
00105         mData   = new char [mMaxLen+1];
00106         memcpy (mData, chrp, mLen);
00107         mData [mMaxLen] = 0x00;
00108     } else {
00109         mLen = mMaxLen = 0;
00110         mData = NULL;
00111     }
00112     mChkSum = 0;
00113 }
00114 
00123 MagiC::String::String (char* str, uint maxLen, bool own) {
00124     if (own)
00125         mData = str;
00126     else
00127         mData = strdup (str);
00128     mData[maxLen] = '\0';
00129     mLen = str? strlen (str) : 0;
00130     mMaxLen = maxLen;
00131     mChkSum = 0;
00132 }
00133 
00134 MagiC::String::~String () {
00135     if (mData) delete mData;
00136     mData = (char*) 0xdddddddd;
00137 }
00138 
00139 template<class TYPE>
00140 inline char* intToString(TYPE value, uint base) {
00141     const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
00142     if (base > sizeof(digits))
00143         throw Exception (strformat ("Too large base %d for integer-to-String conversion", base));
00144     
00145     const int maxintlen = 40;
00146     char buf[maxintlen];
00147     char* loc = buf + (maxintlen-1);
00148     *(loc--) = '\x00'; // Terminate
00149 
00150     bool isNeg = false; // Remember negative sign
00151     if (value < 0) {
00152         isNeg = true;
00153         value = -value;
00154     }
00155 
00156     do {
00157         *(loc--) = digits [value % base];
00158         value /= base;
00159     } while (value);
00160 
00161     if (isNeg) // Add sign if negative
00162         *(loc--) = '-';
00163 
00164     return strdup (loc+1);
00165 }
00166 
00168 MagiC::String::String (int i, int base) {
00169     mData = intToString<int> (i, base);
00170     mLen = mMaxLen = strlen(mData);
00171     mChkSum = 0;
00172 }
00173 
00175 MagiC::String::String (uint i, int base) {
00176     mData = intToString<uint> (i, base);
00177     mLen = mMaxLen = strlen(mData);
00178     mChkSum = 0;
00179 }
00180 
00182 MagiC::String::String (long i, int base) {
00183     mData = intToString<long> (i, base);
00184     mLen = mMaxLen = strlen(mData);
00185     mChkSum = 0;
00186 }
00187 
00188 template <class TYPE>
00189 inline char* formatFloat(TYPE f, char fmt, int prec) {
00190     // Create formatting string
00191     char formatBuf [20];
00192     if (prec >= 0)
00193         sprintf (formatBuf, "%%.%d%c", prec, fmt);
00194     else
00195         sprintf (formatBuf, "%%%c", fmt);
00196 
00197     // Create actual string with the created format
00198     char buf [80+prec]; // Add prec, because it could be "high".
00199     sprintf (buf, formatBuf, f);
00200 
00201     return strdup (buf); // TODO: Use safedup
00202 }
00203 
00205 MagiC::String::String (float f, char fmt, int prec) {
00206     mData = formatFloat<float> (f, fmt, prec);
00207     mLen = mMaxLen = strlen(mData);
00208     mChkSum = 0;
00209 }
00210 
00212 MagiC::String::String (double f, char fmt, int prec) {
00213     mData = formatFloat<double> (f, fmt, prec);
00214     mLen = mMaxLen = strlen(mData);
00215     mChkSum = 0;
00216 }
00217 
00219 String& MagiC::String::assign (char c) {
00220     if (!mData)
00221         mData = new char [2];
00222     mData[0] = c;
00223     mData[1] = '\x00';
00224     mLen = 1;
00225     mChkSum = 0;
00226     return *this;
00227 }
00228 
00233 String& MagiC::String::operator= (const String& other) {
00234     if (&other == NULL || other.mData==NULL || other.mLen==0) {
00235         // The string was null
00236         if (mData) {
00237             mLen    = 0;
00238             mMaxLen = 0;
00239             *mData  = '\x00'; // Preserve it
00240         }
00241     } else {
00242         // The string contains something
00243         mLen = other.mLen;
00244         if (mLen > mMaxLen) { // Reallocate only if necessary
00245             if (mData)
00246                 delete mData;
00247             mMaxLen = mLen;
00248             mData = new char [mMaxLen+1];
00249         }
00250         memcpy (mData, other.mData, mLen+1);
00251     }
00252     mChkSum = other.mChkSum;
00253     return *this;
00254 }
00255 
00260 String& MagiC::String::operator= (const char* chrp) {
00261     if (!chrp || !*chrp) {
00262         // The string was null
00263         if (mData) {
00264             mLen    = 0;
00265             mMaxLen = 0;
00266             *mData  = '\x00'; // Preserve it
00267         }
00268     } else {
00269         // The string has something
00270         mLen = strlen (chrp);
00271         if (mLen > mMaxLen) { // Reallocate only if necessary
00272             if (mData)
00273                 delete mData;
00274             mMaxLen = mLen;
00275             mData = new char [mMaxLen+1];
00276         }
00277         memcpy (mData, chrp, mLen+1);
00278     }
00279     mChkSum = 0;
00280     return *this;
00281 }
00282 
00283 ostream& MagiC::String::dump (ostream& out) const {
00284     out << format ("String #0x%x\n");
00285     out << "mData=" << mData << "\n";
00286     out << "mLen=" << mLen << "\n";
00287     out << "mMaxLen=" << mMaxLen << "\n";
00288     return out;
00289 }
00290 
00296 ostream& MagiC::String::operator>> (ostream& out) const {
00297     // Observe that mData can be NULL, in which case (null) will be written.
00298     out << mData;
00299     return out;
00300 }
00301 
00307 istream& MagiC::String::operator<< (istream& is) {
00308     mLen = 0; // Set size to 0. Warning! Uncommon access!
00309     if (mData)
00310         mData[0] = '\x00';
00311     ensure_spontane (80);
00312     
00313     int w = is.width (0);
00314     if (is.ipfx0 ()) {
00315         register streambuf *sb = is.rdbuf ();
00316         while (1) {
00317             int ch = sb->sbumpc ();
00318             if (ch == EOF) {
00319                 is.setstate (ios::eofbit);
00320                 break;
00321             } else if (isspace (ch)) {
00322                 sb->sungetc ();
00323                 break;
00324             }
00325             (*this) += ch;
00326             if (--w == 1)
00327                 break;
00328         }
00329     }
00330     is.isfx ();
00331     if (mLen == 0) // Didn't read anything. This is a problem. NOTE: REALLY????? Uh...
00332         is.setstate (ios::failbit);
00333  
00334     return is;
00335 }
00336 
00337 CArchive& MagiC::String::operator>> (CArchive& arc) const {
00338     arc.name ("mLen") << mLen;
00339     arc.name ("mMaxLen") << mMaxLen;
00340     if (mLen)
00341         arc.name ("mData").write (mData, mLen+1);
00342     else
00343         arc.name ("mData").write (mData, 0);
00344     return arc;
00345 }
00346 
00347 IStream& MagiC::String::operator<< (IStream& arc) {
00348     arc >> mLen;
00349     arc >> mMaxLen;
00350     delete mData;
00351     mData=NULL;
00352     mChkSum = 0;
00353     if (mLen) {
00354         mData = new char [mMaxLen+1];
00355         arc.read (mData, mLen+1);
00356     }
00357     mChkSum=0;
00358     return arc;
00359 }
00360 
00362 String MagiC::String::operator+ (const String& other) const {
00363     String result = *this;
00364     result += other;
00365     return result;
00366 }
00367 
00369 String MagiC::String::operator+ (const char* str) const {
00370     String result = *this;
00371     result += String(str);
00372     return result;
00373 }
00374 
00378 bool findLowestNum (const String& str, uint& start, uint& end) {
00379     // Scan the string using a state machine.
00380     enum states {NORMAL=0, FOUNDPERCENT};
00381     int state = NORMAL;     // Current state
00382     int number = 0;         // Number currently being scanned
00383     int curPos = 0;         // Starting position of the currently scanned number
00384     int lowest = 999999;    // Lowest number found so far
00385     start = 0;              // Start position of the lowest number found so far
00386     end = 0;                // End position of the lowest number found so far
00387 
00388     for (int i=0; i<str.length(); i++) {
00389         switch (state) {
00390           case NORMAL:
00391               if (str[i] == '%') {
00392                   state = FOUNDPERCENT;
00393                   number = 0;
00394                   curPos = i;
00395               }
00396               break;
00397           case FOUNDPERCENT:
00398               if (isdigit(str[i]))
00399                   number = number*10 + int(str[i]-'0');
00400               else {
00401                   if (number < lowest) {
00402                       // Found a new lowest
00403                       lowest    = number;
00404                       start     = curPos;
00405                       end       = i;
00406                   }
00407                   state = NORMAL;
00408               }
00409               break;
00410         }
00411     }
00412     if (state == FOUNDPERCENT && number < lowest) {
00413         // Found a new lowest in the end of the string
00414         start   = curPos;
00415         end     = str.length();
00416         lowest  = 0;
00417     }
00418 
00419     return (lowest!=999999);
00420 }
00421 
00423 String MagiC::String::arg (const String& replacement, int fieldwidth) const {
00424     uint start, end;
00425     if (findLowestNum (*this, start, end)) {
00426         int realwidth = (replacement.length()>fieldwidth)? replacement.length() : fieldwidth;
00427         int maxLen = start + realwidth + (length()-end);
00428         char* buf = new char[maxLen + 1];
00429         char* resultPos = buf;
00430 
00431         // Concatenate beginning of the string, if not in the beginning
00432         if (start>0) {
00433             memcpy (resultPos, mData, start);
00434             resultPos += start;
00435         }
00436 
00437         // Concatenate replacement (with padding)
00438         if (realwidth>0) {
00439             for (int padding = (realwidth>fieldwidth)? 0 : fieldwidth-replacement.length(); padding>0; padding--)
00440                 *(resultPos++) = ' ';
00441             memcpy (resultPos, replacement.mData, replacement.length());
00442             resultPos += replacement.length();
00443         }
00444 
00445         // Concatenate rest of the string, if not at end
00446         if (end < mLen) {
00447             memcpy (resultPos, mData+end, mLen-end);
00448             resultPos += mLen-end;
00449         }
00450         *resultPos = '\x00';
00451 
00452         // Create return object using the buffer.
00453         return String (buf, maxLen, true);
00454     } else
00455         // This is an error situation, basicly, but we return something nevertheless.
00456         return *this;
00457 }
00458 
00470 String& MagiC::String::dellast (uint n) {
00471     if (!mData)
00472         return *this;
00473 
00474     // Delete at most the length of the string
00475     if (n>=mLen)
00476         n = mLen;
00477     mLen -= n;
00478     mData[mLen] = 0;
00479     mChkSum = 0;
00480     return *this;
00481 }
00482 
00484 void MagiC::String::chop () {
00485     while (mLen>0 && isspace(mData[mLen-1]))
00486         dellast (1);
00487     mChkSum=0;
00488 }
00489 
00495 int MagiC::String::fast_isequal (const String& other) const {
00496     if (other.mChkSum == mChkSum)
00497         return operator== (other.mData);
00498     else
00499         return 0;
00500 }
00501 
00508 String& MagiC::String::hexcode (const String& other) {
00509     const char hexcodes[] = "0123456789abcdef";
00510     int otherlen = other.length();
00511     ensure (otherlen*2);
00512     for (int i=0; i<otherlen; i++) {
00513         *this += hexcodes [((unsigned int) other.mData[i])/16];
00514         *this += hexcodes [((unsigned int) other.mData[i])%16];
00515     }
00516     mChkSum=0;
00517     return *this;
00518 }
00519 
00526 void MagiC::String::quote (char quotechar='%', int flags=0) {
00527     FORBIDDEN; // Not implemented
00528 }
00529 
00537 void MagiC::String::unquote (char quotechar, int flags) {
00538     enum    {Waiting, GotEqual, GotFirst, GotSoftLinebreak};
00539     String  hextable = "0123456789ABCDEF";
00540     int     state = Waiting,
00541             value = 0,
00542             respos = 0;
00543 
00544     // Merkkijono johon merkit käännöksen jälkeen tallennetaan
00545     // ja kopioidaan tästä lopussa takaisin.
00546     String tmp;
00547     tmp.reserve (mLen);
00548 
00549     // Käydään itsemme läpi
00550     for (int i=0 ; i<mLen ; i++) {
00551         char c=(*this)[i];
00552         switch (state) {
00553             case Waiting:
00554                 if (c == quotechar)
00555                     state=GotEqual;
00556                 else
00557                     if (c=='+' && (flags&QUOTE_HTML))
00558                         tmp += ' ';
00559                     else
00560                         tmp += c;
00561                 break;
00562             case GotEqual:
00563                 if ((value=hextable.find(c)) != -1) {
00564                     state=GotFirst;
00565                     value*=16; // Shiftataan ylöspäin....
00566                 } else { // Hmm, ei ollutkaan heksaluku...
00567                     if (c=='\r') { // soft CRLF
00568                         state = GotSoftLinebreak;
00569                     } else {
00570                         // Something weird...
00571                         // Error in Q-P code! Let's recover it...
00572                         state = Waiting;
00573                         tmp += quotechar; 
00574                         tmp += c;
00575                     }
00576                 }
00577                 break;
00578             case GotFirst:
00579                 if (hextable.find(c) != -1) {
00580                     value+=hextable.find (c);
00581                     tmp += char(value);
00582                     state=Waiting; // Ok, palataan normaaliin tilaan...
00583                 } else {
00584                     // Jotain omituista, virhe QP-koodista.. yritetään toipua..
00585                     tmp += quotechar;
00586                     tmp += char(value);
00587                     tmp += c;
00588                     state = Waiting; // Så vi ventar igen..
00589                 }
00590                 break;
00591             case GotSoftLinebreak:
00592                  // Hmm, se ei ollutkaan pehmeä rivinvaihto??
00593                  if (c!='\n')
00594                     // no, yritetään toipua jollain lailla....
00595                     tmp += c;
00596                 state=Waiting;
00597                 break;
00598         };
00599     }
00600 
00601     if (state!= Waiting) {
00602         // Hmm, siellä oli siis lopussa yksinäinen '=' -> PANIC!
00603         tmp += '=';
00604         if (state==GotFirst)
00605             // DOUBLEPANIC!, mutta varaudutaan silti...
00606             // Hmm, tätä ei pitäisi tarvita tehdä...
00607             tmp += char(hextable[state/16]);
00608     } // DON'T PANIC!
00609 
00610     // Laitetaan loppunulli
00611     // tmp += '\x00';
00612     // tmp.mLen = respos;
00613 
00614     (*this) = tmp;
00615 }
00616 
00618 String MagiC::String::mid (uint from, int n) const {
00619     String result;
00620     
00621     // Jos pituus on -1, otetaan loput merkkijonosta
00622     if (n==-1)
00623         n = mLen-from;
00624 
00625     // Jos pyydetään merkkijonon ulkopuolelta tai tyhjä jono
00626     if (from >= mLen || mLen==0)
00627         return "";
00628 
00629     // Jos pyyntö menee merkkijonon ulkopuolelle, pienennetään pyyntöä
00630     if (((from + n) > mLen))
00631         n = mLen-from;
00632 
00633     ASSERT (mMaxLen>=n);
00634     
00635     // Luodaan uusi merkkijono
00636     result.mLen = n;
00637     result.mMaxLen = mMaxLen;
00638     result.mData = new char [mMaxLen+1];
00639     strncpy (result.mData, mData+from, n);
00640     result.mData [n] = 0;
00641 
00642     return result;
00643 }
00644 
00646 String MagiC::String::left (uint n) const {
00647     return mid (0, n);
00648 }
00649 
00651 String MagiC::String::right (uint n) const {
00652     String result;
00653     
00654     if (n < mLen)
00655         result = mid (mLen-n);
00656     else
00657         result = *this;
00658 
00659     return result;
00660 }
00661 
00666 int MagiC::String::find (const String& subs, uint n) const {
00667     for (int i=n; i <= (mLen-subs.mLen); i++)
00668         if (!strncmp (mData+i, subs.mData, subs.mLen))
00669             return i;
00670     return -1;
00671 }
00672 
00677 int MagiC::String::find (const char c, uint n) const {
00678     char* pos = (char*) memchr (mData+n, c, mLen);
00679     return pos? pos-mData : -1;
00680 }
00681 
00689 int MagiC::String::findRev (const String& subs, int n) const {
00690     if (n<0)
00691         n += mLen;
00692     for (int i=n; i>=0; i--)
00693         if (!strncmp (mData+i, subs.mData, subs.mLen))
00694             return i;
00695     return -1;
00696 }
00697 
00698 String* MagiC::String::clone () const {
00699     return new String (*this);
00700 }
00701 
00703 String& MagiC::String::operator+= (const String& other) {
00704     // Varmistutaan ettei toinen ole tyhjä
00705     if (!other.mLen)
00706         return *this;
00707 
00708     // Ensure that our buffer is large enough
00709     if (mLen+other.mLen > mMaxLen)
00710         ensure (mLen + other.mLen + 1);
00711 
00712     memcpy (mData+mLen, other.mData, other.mLen+1);
00713     mLen += other.mLen;
00714     mData[mLen]='\x00';
00715     mChkSum=0;
00716     return *this;
00717 }
00718 
00720 int MagiC::String::operator== (const char* other) const {
00721     if (!this)
00722         return 0;
00723     if (mData && other)
00724         return (!strcmp (mData, other));
00725     if ((!mData) && (!other))
00726         return 1;
00727     return 0;
00728 }
00729 
00734 int MagiC::String::operator== (const Comparable& other) const {
00735     if (getclass().issameclass (other))
00736         return operator== ((const String&) other);
00737     else
00738         return 0;
00739 }
00740 
00746 String& MagiC::String::operator+= (char c) {
00747     ensure_spontane (mLen+1);
00748     mData [mLen++] = c;
00749     mData [mLen] = 0;
00750     mChkSum=0;
00751     return *this;
00752 }
00753 
00757 void MagiC::String::reserve (int amount) {
00758     if (mData) {
00759         char* newmData = new char [amount+1];
00760         if (!newmData)
00761             throw runtime_error ("Out of memory or something in MagiC::String::reserve()");
00762         memcpy (newmData, mData, mLen+1);
00763         delete mData;
00764         mData = newmData;
00765         mData [amount] = 0x00;
00766     } else {
00767         mData = new char[amount+1];
00768         if (!mData)
00769             throw runtime_error ("Out of memory or something in MagiC::String::reserve()");
00770         *mData = 0x00;
00771     }
00772     mMaxLen = amount;
00773 }
00774 
00792 /*
00793 const char& MagiC::String::operator[] (uint n) const {
00794     if (n<mLen)
00795         return mData [n];
00796     else
00797         throw Exception ("String index out of bounds");
00798 }
00799 */
00800 
00802 /*
00803 char& MagiC::String::operator[] (uint n) {
00804     if (n<mLen)
00805         return mData [n];
00806     else {
00807         throw Exception ("String index out of bounds");
00808         return *mData; // To get rid of a warning
00809     }
00810 }
00811 */
00812 
00816 void MagiC::String::split (Array<String>& trg, const char delim) const {
00817     if (!this || !mLen)
00818         return;
00819     char* tmp = new char [mLen+1];
00820     memcpy (tmp, mData, mLen+1);
00821     tmp[mLen]=0;
00822     for (int i=0; i<mLen; i++)
00823         if (tmp[i]==delim)
00824             tmp[i]=0;
00825     trg.empty ();
00826     for (int pos = 0, i=0; pos<mLen; pos+=strlen (tmp+pos)+1, i++) {
00827         String tmps = tmp+pos;
00828         trg.put (tmps, i);
00829     }
00830     delete tmp;
00831 }
00832 
00836 void MagiC::String::join (const Array<String>& src, const char delim) {
00837     // Lasketaan kohdemerkkijonon pituus tilanvarausta varten
00838     int newlen = src.size-1;
00839     for (int i=0; i<src.size; i++)
00840         newlen += src[i].length();
00841 
00842     // Varataan tila
00843     reserve (newlen);
00844     *this = "";
00845 
00846     // Katenoidaan merkkijonot
00847     for (int i=0; i<src.size; i++) 
00848         if (!src[i].isEmpty ()) {
00849             *this += src[i];
00850             if (i<src.size-1)
00851                 *this += delim;
00852         }
00853 
00854     mChkSum=0;
00855 }
00856 
00860 String MagiC::String::stripWhiteSpace () const {
00861     int s=0, e=mLen;
00862     while (s<mLen && strchr (" \t\r\n",(*this)[s])) // TODO: Add ff, vt
00863         s++;
00864     while (e>s && strchr (" \t\r\n",(*this)[e-1])) // TODO: Add ff, vt
00865         e--;
00866     return mid (s, e-s);
00867 }
00868 
00873 String MagiC::String::simplifyWhiteSpace () const {
00874     if (mLen == 0)
00875         return String();
00876 
00877     char*   buffer  = new char[mLen+1]; // Add 1 for terminating \x00
00878     char*   trgPos  = buffer;
00879     int     pos     = 0;
00880 
00881     // Strip whitespace from beginning
00882     for (pos=0; pos<mLen; pos++)
00883         if (!isspace(mData[pos]))
00884             break;
00885 
00886     // Strip duplicate whitespaces
00887     bool oneWhitespace=false;
00888     for (; pos<mLen; pos++) {
00889         if (isspace(mData[pos])) {
00890             if (!oneWhitespace)
00891                 *(trgPos++) = mData[pos];
00892             oneWhitespace = true;
00893         } else {
00894             *(trgPos++) = mData[pos];
00895             oneWhitespace = false;
00896         }
00897     }
00898 
00899     // Strip whitespace from end (there can be only one)
00900     if (isspace (*(trgPos-1)))
00901         trgPos--;
00902     *trgPos = '\x00';
00903 
00904     if (trgPos > buffer)
00905         // Construct using the buffer.
00906         return String (buffer, mLen+1, true);
00907     else {
00908         // The string became empty -> return really empty string.
00909         delete buffer;
00910         return String ();
00911     }
00912 }
00913 
00914 void MagiC::String::upper() const {
00915     for (int i=0; i<mLen; i++)
00916         mData[i] = toupper (mData[i]);
00917 }
00918 
00919 void MagiC::String::lower() const {
00920     for (int i=0; i<mLen; i++)
00921         mData[i] = tolower (mData[i]);
00922 }
00923 
00929 int MagiC::String::regmatch (const char* expr) const {
00930     if (!mData)
00931         return 0;
00932     RegExp rexp (expr);
00933     return rexp.match (mData);
00934 }
00935 
00946 int MagiC::String::regmatch (const char* expr, Array<String>& target) const {
00947     if (!mData)
00948         return 0;
00949     RegExp rexp (expr);
00950     return rexp.match (*this, target);
00951 }
00952 
00955 int MagiC::String::regmatch (RegExp& compiled, Array<String>& target) const {
00956     if (!mData)
00957         return 0;
00958     return compiled.match (*this, target);
00959 }
00960 
00973 char MagiC::String::checksum () {
00974     mChkSum=0;
00975     hashfunc (256);
00976     return mChkSum;
00977 }
00978 
00992 int MagiC::String::hashfunc (int hashsize) const {
00993     ASSERTWITH (hashsize<=256, format ("String hash size maximum is 256 slots",
00994                                        " (hashsize was %d)", hashsize));
00995     
00996     // Jos on checksum laskettu, palautetaan sen mukainen arvo
00997     if (mChkSum)
00998         return mChkSum % hashsize;
00999 
01000     int sum=0;
01001     if (!mLen)
01002         return 0;
01003 
01004     if (mLen < 10) {
01005         // Lyhyille merkkijonoille
01006         
01007         for (int i=0; i<mLen; i++)
01008             sum += mData[i];
01009 
01010         (unsigned char&) mChkSum = sum % 256;
01011     } else {
01012     // Pitemmille merkkijonoille
01013 
01014         // Sum of the first, middle and last character
01015         sum = int(mData[0]) + int(mData[mLen/2]) + mLen*int(mData[mLen-1]);
01016 
01017         (unsigned char&) mChkSum = sum % 256;
01018     }
01019 
01020     // TRACE4 ("%s -> %d/%d/%d", mData, sum, int(mChkSum), int(mChkSum%hashsize));
01021     return mChkSum % hashsize;
01022 }
01023 
01029 /*
01030 MagiC::String::operator float () const {
01031     if (mData) {
01032         char* tmp = strdup (mData);
01033         for (char* tmp_p=tmp; *tmp_p; tmp_p++)
01034             if (*tmp_p == ',')
01035                 *tmp_p = '.';
01036         float res = atof (tmp);
01037         free (tmp);
01038         return res;
01039     }
01040     return 0;
01041 }
01042 */
01043 
01044 
01046 //                                     |                              o                  //
01047 //  ___       |   ___        _    ___  |     __         _    ___   |           _    ____ //
01048 // /   ) \ / -+- /   ) |/\ |/ \   ___| |    /   |   | |/ \  |   \ -+- |  __  |/ \  (     //
01049 // |---   X   |  |---  |   |   | (   | |    +-- |   | |   | |      |  | /  \ |   |  \__  //
01050 //  \__  / \   \  \__  |   |   |  \__| |    |    \__! |   |  \__/   \ | \__/ |   | ____) //
01051 //                                          |                                            //
01053 
01055 const String MagiC::emptystring;
01056 
01066 char* MagiC::strnchr (const char* str, int mLen, char c) {
01067     const char* pos=str;
01068     for (int i=0; i<mLen; i++, pos++)
01069         if (*pos == c)
01070             return (char*) pos;
01071     return NULL;
01072 }
01073 
01082 char* safedup (const char* orig, int maxlen=-1) {
01083     if (orig) {
01084         // Duplicate.
01085         // We can't use strdup, because ANSI C++ doesn't have it.
01086         int len = strlen (orig)+1; // Length with end-null.
01087         char* result = new char [len];
01088         memcpy (result, orig, len);
01089         return result;
01090     } else
01091         return (char*) NULL;
01092 }
01093 
01098 int MagiC::fgetS (FILE* in, String& str) {
01099     char    cbuff [4097],
01100             *nlpos;
01101     int mLen=0;
01102 
01103     str = "";
01104 
01105     do {
01106         // Luetaan yksi lohko
01107         fgets (cbuff, 4096, in);
01108 
01109         // Katsotaan onko lohkossa yhtään rivinvaihtoa
01110         nlpos = strnchr (cbuff, 4096, '\n');
01111 
01112         // Määritellään luetun lohkon pituus
01113         mLen = nlpos? nlpos-cbuff+1 : 4096;
01114 
01115         // Muunnetaan Stringiksi
01116         String tmp (cbuff, mLen);
01117 
01118         // Lisätään tulosmerkkijonoon
01119         str += tmp;
01120 
01121         // Toistetaan kunnes löydetään lohkosta rivinvaihto
01122     } while (!nlpos && !feof (in));
01123 
01124     if (feof (in))
01125         mLen = -1;
01126 
01127     return mLen;
01128 }
01129 
01134 istream& MagiC::getS    (istream& is, String& str, char term) {
01135     str = ""; // TODO: This may shorten the maxlen?
01136     str.ensure_spontane (80);
01137     
01138     register streambuf *sb = is.rdbuf ();
01139     bool eof=false;
01140     while (true) {
01141         int ch = sb->sbumpc ();
01142         if (ch == EOF) {
01143             eof = true;
01144             is.setstate (ios::eofbit);
01145             break;
01146 
01147             // Separation with given character, or whitespace, if
01148             // the terminator is \xff.
01149         } else if ((term!='\xff' && ch==term) || (term=='\xff' && isspace (ch)))
01150             break;
01151         
01152         // Skip CR
01153         else if (term!='\n' || ch!='\r')
01154             str += char(ch);
01155     }
01156 
01157     if (eof && str.length()==0)
01158         is.setstate (ios::failbit);
01159 
01160     return is;
01161 }
01162 
01163 void nullcharspace (int charspace [256]) {
01164     for (int i=0; i<256; i++)
01165         charspace [i]=0;
01166 }
01167 
01169 void MagiC::loadString (String& str, const String& filename) {
01170     FILE* in = fopen (filename, "rb");
01171     if (!in)
01172         return;
01173     str = "";
01174     String buff;
01175     buff.reserve (200);
01176     while (!feof(in)) {
01177         fgetS (in, buff);
01178         str += buff;
01179     }
01180     fclose (in);
01181 }
01182 
01191 String MagiC::strformat (const char* sformat, ...) {
01192     char format_buff[1024];
01193     va_list args;
01194     
01195     va_start (args, sformat);
01196     // fmt = va_arg(args, char*);
01197     int i=vsprintf (format_buff, sformat, args);
01198     va_end (args);
01199 
01200     ASSERTWITH (i<1024, "String format result exceeded buffer size (1024 bytes)");
01201     return format_buff;
01202 }
01203 
01204 

Generated at Tue Dec 4 19:53:27 2001 for MagiC++ by doxygen1.2.6 written by Dimitri van Heesch, © 1997-2001