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
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);
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);
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';
00158
00159 bool isNeg = false;
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)
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
00201 char formatBuf [20];
00202 if (prec >= 0)
00203 sprintf (formatBuf, "%%.%d%c", prec, fmt);
00204 else
00205 sprintf (formatBuf, "%%%c", fmt);
00206
00207
00208 char buf [80+prec];
00209 sprintf (buf, formatBuf, f);
00210
00211 return strdup (buf);
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
00254 ensure_spontane (mLen + 1);
00255
00256 mData[mLen++] = c;
00257 mData[mLen] = '\x00';
00258 mChkSum = 0;
00259
00260 return *this;
00261 }
00262
00269 String& MagiC::String::append (const char* str,
00270 uint strlength )
00271 {
00272
00273 if (!str || strlength==0)
00274 return *this;
00275
00276
00277 if (mLen + int(strlength) > mMaxLen)
00278 ensure (mLen + strlength + 1);
00279
00280
00281 memcpy (mData+mLen, str, strlength);
00282
00283 mLen += strlength;
00284 mData[mLen] = '\x00';
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
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
00335 if (mData) {
00336 mLen = 0;
00337 *mData = '\x00';
00338 }
00339 } else {
00340
00341 mLen = other.mLen;
00342 if (mLen > mMaxLen) {
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
00362 if (mData) {
00363 mLen = 0;
00364 *mData = '\x00';
00365 }
00366 } else {
00367
00368 mLen = strlen (chrp);
00369 if (mLen > mMaxLen) {
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
00383
00384
00385
00386
00387
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 ();
00441 while (1) {
00442
00443 int ch = dev->getch();
00444
00445
00446
00447
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
00460
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
00520 enum states {NORMAL=0, FOUNDPERCENT};
00521 int state = NORMAL;
00522 int number = 0;
00523 int curPos = 0;
00524 int lowest = 999999;
00525 start = 0;
00526 end = 0;
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
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
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
00574 if (start > 0) {
00575 memcpy (resultPos, mData, start);
00576 resultPos += start;
00577 }
00578
00579
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
00588 if (end < (uint) mLen) {
00589 memcpy (resultPos, mData+end, mLen-end);
00590 resultPos += mLen-end;
00591 }
00592 *resultPos = '\x00';
00593
00594
00595 return String (buf, maxLen, true);
00596 } else
00597
00598 return *this;
00599 }
00600
00611
00614 String& MagiC::String::dellast (uint n)
00615 {
00616 if (!mData)
00617 return *this;
00618
00619
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;
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;
00691
00692 tmp.reserve (mLen);
00693
00694
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"E_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;
00712 } else {
00713 if (c=='\r') {
00714 state = GotSoftLinebreak;
00715 } else {
00716
00717
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;
00730 } else {
00731
00732 tmp += quotechar;
00733 tmp += char(value);
00734 tmp += c;
00735 state = Waiting;
00736 }
00737 break;
00738
00739 case GotSoftLinebreak:
00740
00741 if (c!='\n')
00742
00743 tmp += c;
00744 state=Waiting;
00745 break;
00746 };
00747 }
00748
00749 if (state!= Waiting) {
00750
00751 tmp += '=';
00752 if (state==GotFirst)
00753
00754
00755 tmp += char(hextable[uint(state/16)]);
00756 }
00757
00758
00759
00760
00761
00762 (*this) = tmp;
00763 }
00764
00766 String MagiC::String::mid (uint from, int n) const {
00767 String result;
00768
00769
00770 if (n==-1)
00771 n = mLen-from;
00772
00773
00774 if (from >= (uint) mLen || mLen==0)
00775 return "";
00776
00777
00778 if (((from + n) > (uint) mLen))
00779 n = mLen-from;
00780
00781 ASSERT (mMaxLen>=n);
00782
00783
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
00912
00913
00914
00915
00916
00917
00918
00920
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00934 void MagiC::String::split (Array<String>& trg, const char delim) const {
00935 if (!this || !mLen)
00936 return;
00937
00938
00939 char* tmp = new char [mLen+1];
00940 memcpy (tmp, mData, mLen+1);
00941 tmp[mLen]=0;
00942
00943
00944 for (int i=0; i<mLen; i++)
00945 if (tmp[i]==delim)
00946 tmp[i]=0;
00947
00948
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
00962 int newlen = src.size() - 1;
00963 for (int i=0; i<src.size(); i++)
00964 newlen += src[i].length();
00965
00966
00967 reserve (newlen);
00968 *this = "";
00969
00970
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]))
00987 s++;
00988 while (e>s && strchr (" \t\r\n",(*this)[e-1]))
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];
01002 char* trgPos = buffer;
01003 int pos = 0;
01004
01005
01006 for (pos=0; pos<mLen; pos++)
01007 if (!isspace(mData[pos]))
01008 break;
01009
01010
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
01024 if (isspace (*(trgPos-1)))
01025 trgPos--;
01026 *trgPos = '\x00';
01027
01028 if (trgPos > buffer)
01029
01030 return String (buffer, mLen+1, true);
01031 else {
01032
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
01136 if (mChkSum)
01137 return mChkSum % hashsize;
01138
01139 if (!mLen)
01140 return 0;
01141
01142 int sum = 0;
01143 if (mLen < 10) {
01144
01145
01146 for (int i=0; i<mLen; i++)
01147 sum += mData[i];
01148
01149 (unsigned char&) mChkSum = sum % 256;
01150 } else {
01151
01152
01153
01154 sum = int(mData[0]) + int(mData[mLen/2]) + mLen*int(mData[mLen-1]);
01155
01156 (unsigned char&) mChkSum = sum % 256;
01157 }
01158
01159
01160 return mChkSum % hashsize;
01161 }
01162
01168
01169
01170
01171
01172
01173
01174
01175
01176
01177
01178
01179
01180
01181
01182
01183
01185
01186
01187
01188
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
01224
01225 int len = strlen (orig)+1;
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
01245 char* callResult = fgets (cbuff, 4096, in);
01246
01247 if (callResult == NULL)
01248 break;
01249
01250
01251 nlpos = strnchr (cbuff, 4096, '\n');
01252
01253
01254 int blocklength = nlpos? nlpos-cbuff+1 : 4096;
01255
01256
01257 str.append (cbuff, blocklength);
01258
01259 bytesread += blocklength;
01260
01261
01262 } while (!nlpos && !feof (in));
01263
01264 return bytesread;
01265 }
01266
01271 istream& MagiC::getS (istream& is, String& str, char term) {
01272 str = "";
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
01285
01286 } else if ((term!='\xff' && ch==term) || (term=='\xff' && isspace (ch)))
01287 break;
01288
01289
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
01343 char* buffer = new char [STRFORMAT_SMALL_BUFFER_SIZE + 1];
01344
01345
01346 int written = vsnprintf (buffer, STRFORMAT_SMALL_BUFFER_SIZE + 1, sformat, ap);
01347
01348 if (written > STRFORMAT_SMALL_BUFFER_SIZE) {
01349
01350 delete buffer;
01351 buffer = new char [written+1];
01352
01353
01354 vsnprintf (buffer, written+1, sformat, ap);
01355 }
01356
01357 return String (buffer, String::STRCRFL_OWN);
01358 }
01359
01360 END_NAMESPACE;
01361