Adapted to recent changes of %build_linklib.
[AROS-Contrib.git] / FryingPan / framework / Generic / String.cpp
blob1c5c366a166b461b9f152bc8782080109e924760
1 /*
2 * Amiga Generic Set - set of libraries and includes to ease sw development for all Amiga platforms
3 * Copyright (C) 2001-2011 Tomasz Wiszkowski Tomasz.Wiszkowski at gmail.com.
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include "String.h"
21 #include "LibrarySpool.h"
22 #include <libclass/exec.h>
23 #include <libclass/dos.h>
24 #include <libclass/utility.h>
25 #include <LibC/LibC.h>
26 #include "Debug.h"
28 using namespace GenNS;
30 #if defined(mc68000)
31 static unsigned long ___vFormatFunc[] =
32 { 0x16c04e75, 0x4e754e75 };
33 #endif
35 struct RawDoFmtStruct
37 char *buff;
38 int currlen;
39 int maxlen;
44 void String::Update()
46 lLength = strlen((const char*)sContents);
49 void String::SetLength(unsigned long lLen)
51 if (lLen >= lMaxLen)
52 ReallocBuf(lLen + 1);
53 if (lLen >= lMaxLen)
54 lLen = lMaxLen - 1;
56 lLength = lLen;
57 sContents[lLen] = 0;
60 String::String()
62 lMaxLen = 0;
63 lLength = 0;
64 sContents = 0;
65 Assign((char*)0);
68 String::String(const char* s)
70 lMaxLen = 0;
71 lLength = 0;
72 sContents = 0;
73 Assign(s);
76 String::String(const String &s)
78 lMaxLen = 0;
79 lLength = 0;
80 sContents = 0;
81 Assign(s.Data());
84 String::~String()
86 if (sContents)
87 delete sContents;
90 const char* String::Data(void) const
92 if (!sContents) return "";
93 return (char*)sContents;
96 void String::Clone(const char* sSrc, unsigned int lLen)
98 if (lLen >= lMaxLen) // not enough space?
99 AllocBuf(lLen + 1); // make enough.
100 if (lLen >= lMaxLen) // failed?
101 return; // return immediately.
102 if (lLen > 0) // if there is something to copy,
103 memcpy(sContents, sSrc, lLen); // literally CLONE memory
104 lLength = lLen; // update length ;)
105 sContents[lLen] = 0; // pad with zeros.
108 void String::Assign(const char *s)
110 // VPrintf("Assigning %s (%lx)\n", ARRAY((int)s));
111 if (0 == s) // string not passed?
112 Clone(0, 0); // create an empty string (NO REALLOC)
113 else // otherwise
114 Clone(s, strlen(s)); // clone what we have.
115 // VPrintf("Assigned %s (%lx)\n", ARRAY((int)sContents));
118 void String::Assign(const String *s)
120 if (0 == s) // if no string has been passed
121 Clone(0, 0); // create empty one
122 else // otherwise
123 Clone(s->Data(), s->Length()); // use what we have.
126 int String::Length() const
128 return lLength; // this one is easy.
131 String::operator char*(void) const
133 return (char *)Data(); // this one is easy, too
136 String::operator unsigned char*(void) const
138 return (unsigned char*)Data(); // humm
141 String &String::operator = (const String & sStr)
143 Assign(const_cast<String*>(&sStr)); // okay...
144 return *this; //
147 String &String::operator = (const int64 sVal)
149 if ((sVal & 0xffffffff) == sVal)
151 FormatStr("%ld", ARRAY(sVal)); // aint hard i guess..
153 else
155 FormatStr("0x%lx%08lx", ARRAY((sVal >> 32) & 0xffffffff, sVal & 0xffffffff));
157 return *this; // is it..
160 int String::operator < (const String sStr) const
162 return 0 > strncmp(Data(), sStr.Data(), Length()); // humm..
165 int String::operator == (const String sStr) const
167 return 0 == strncmp(Data(), sStr.Data(), Length()); // humm..
170 int String::operator < (const char* sStr) const
172 return 0 > strncmp(Data(), sStr, Length()); // compare only what we are aware of.
175 int String::operator == (const char* sStr) const
177 return 0 == strncmp(Data(), sStr, Length()); // compare only what we are aware of.
180 int String::FormatStr(const char *sFmtStr, void*pParams)
182 char *temp = new char[65535];
183 ASSERT(Exec != 0);
184 #if defined(__amiga__) & defined(mc68000)
185 Exec->RawDoFmt(sFmtStr, pParams, &___vFormatFunc, temp);
186 #elif defined(__AMIGAOS4__)
187 Exec->RawDoFmt(sFmtStr, pParams, 0, temp);
188 //VSNPrintf((uint8*)temp, 65535, (uint8*)sFmtStr, pParams);
189 #elif !defined(__LINUX__)
190 Exec->RawDoFmt(sFmtStr, pParams, 0, temp);
191 #else
192 vsprintf(temp, sFmtStr, (va_list)pParams);
193 #endif
194 Assign(temp);
195 delete [] temp;
196 return 0;
199 void String::AddPath(const char* sElement)
201 if ((strlen(sElement) + lLength) >= (lMaxLen-4)) // if you need,
202 ReallocBuf(strlen(sElement) + lLength + 5); // get more mem
203 if ((strlen(sElement) + lLength) >= (lMaxLen-4)) // if we failed
204 return; // abort.
205 DOS->AddPart((char*)sContents, sElement, lMaxLen); // otherwise update
206 Update();
209 void String::AllocBuf(unsigned int lSize)
211 unsigned char *sOld;
213 if (lSize <= lMaxLen) // dont care if we dont have to
214 return; // :)
216 sOld = sContents; // backup old stuff.
217 sContents = new unsigned char[lSize+1];
219 if (0 != sContents) // if everything went smooth
220 { //
221 if (0 != sOld) //
222 delete [] sOld;
223 lMaxLen = lSize + 1; // and update the size.
225 else
227 request("Low memory error", "Unable to allocate %ld bytes of memory", "Continue", ARRAY(lSize));
228 sContents = sOld; // revert changes,
230 sContents[0] = 0; // also update the length
231 lLength = 0; // etc...
234 void String::ReallocBuf(unsigned int lSize)
236 unsigned char *sOld;
238 if (lSize <= lMaxLen) // dont care if we dont have to
239 return; // :)
241 sOld = sContents; // backup old stuff.
242 sContents = new unsigned char[lSize + 1]; // get fresh piece of mem :P
244 if (0 != sContents) // if everything went smooth
245 { //
246 if (0 != sOld) //
248 memcpy(sContents, sOld, lLength);// copy the whole old block of memory :)
249 delete [] sOld;
251 else
253 lLength = 0;
255 lMaxLen = lSize + 1; // and update the size.
257 else
259 request("Low memory error", "Unable to allocate %ld bytes of memory", "Continue", ARRAY(lSize));
260 sContents = sOld; // revert changes,
262 sContents[lLength] = 0; // make sure no garbage follows.
265 String String::operator + (const char *sStr)
267 String s(*this); // this should be easy
268 s += sStr; // i hope..
269 return s; // :P
272 String String::operator + (const String & sStr)
274 String s(*this); // same here.
275 s += sStr.Data(); // hope i dont screw up
276 return s; // or else bad things may happen
279 String &String::operator += (const char *sStr)
281 if ((strlen(sStr)+lLength) >= lMaxLen) // if you need
282 ReallocBuf(strlen(sStr)+lLength+1); // get more mem
283 if ((strlen(sStr)+lLength) >= lMaxLen) // if you fail
284 return *this; // do not proceed.
286 strncat((char*)sContents, sStr, lMaxLen); // update as much as we can take.
287 Update();
288 return *this;
291 String &String::operator += (const char cChar)
293 if ((1+lLength) >= lMaxLen) // if you need
294 ReallocBuf(lLength+16); // get more mem
295 if ((1+lLength) >= lMaxLen) // if you fail
296 return *this; // do not proceed.
298 sContents[lLength++] = cChar;
299 sContents[lLength] = 0;
300 Update();
301 return *this;
304 unsigned long String::TrimChars(const char* sChars)
306 int lNewStart = 0;
307 int lNewEnd = Length();
308 int lInPos;
311 for (lInPos = 0; sChars[lInPos]; ++lInPos)
313 if (sContents[lNewStart] == sChars[lInPos])
315 ++lNewStart;
316 if (lNewStart >= lNewEnd)
317 break;
318 lInPos = -1;
322 for (lInPos = 0; sChars[lInPos]; ++lInPos)
324 if (sContents[lNewEnd-1] == sChars[lInPos])
326 --lNewEnd;
327 if (lNewEnd == 0)
328 break;
329 sContents[lNewEnd] = 0;
330 lInPos = -1;
334 String sTemp((char*)&sContents[lNewStart]);
335 *this = sTemp;
336 return Length();
339 char &String::operator [] (int lOffset)
341 ASSERT(lOffset >= 0);
342 ASSERT(lOffset <= (int)lMaxLen);
343 return (char&)sContents[lOffset];
346 String String::SubString(int lFirst, int lLen)
348 String s;
349 int pos;
351 if (lLen == -1)
353 lLen = Length() - lFirst;
356 s.AllocBuf(lLen+1);
357 for (pos=0; pos<lLen; pos++)
359 if (!sContents[lFirst+pos])
360 break;
361 s[pos] = sContents[lFirst+pos];
363 s[pos] = 0;
364 s.Update();
365 return s;
368 String String::LeftString(int lLen)
370 return SubString(0, lLen);
373 String String::RightString(int lLen)
375 return SubString (Length()-lLen, lLen);
378 bool String::Equals(const char* sOther)
380 return (0 == strcmp((char*)sContents, sOther));
383 bool String::EqualsIgnoreCase(const char* sOther)
385 return (0 == stricmp((char*)sContents, sOther));
388 int String::Compare(const char* sOther) const
390 return (strcmp((char*)sContents, sOther));
393 int String::CompareIgnoreCase(const char* sOther) const
395 return (stricmp((char*)sContents, sOther));
398 int32 String::ToLong()
400 enum eType
402 E_Dec = 0,
403 E_Bin,
404 E_Oct,
405 E_Hex
408 char c;
409 int32 lValue = 0;
410 eType lType = E_Dec;
412 for (unsigned int i=0; sContents[i]; i++)
414 if (i >= lLength)
415 break;
416 c = sContents[i];
417 if ((lValue == 0) && (i == 1))
419 if (c == 'x')
420 lType = E_Hex;
421 else if (c == 'b')
422 lType = E_Bin;
423 else
424 lType = E_Oct;
427 switch (lType)
429 case E_Dec:
430 if ((c < '0') || (c > '9'))
431 return lValue;
432 lValue *= 10;
433 lValue += (c-'0');
434 break;
435 case E_Bin:
436 if ((c < '0') || (c > '1'))
437 return lValue;
438 lValue <<= 1;
439 lValue += (c-'0');
440 break;
441 case E_Oct:
442 if ((c < '0') || (c > '7'))
443 return lValue;
444 lValue <<= 3;
445 lValue += (c-'0');
446 break;
447 case E_Hex:
448 if (((c < '0') || (c > '9')) &&
449 ((c < 'a') || (c > 'f')) &&
450 ((c < 'A') || (c > 'F')))
451 return lValue;
453 if (c < '9')
454 c -= '0';
455 else if (c < 'F')
456 c -= ('A'-10);
457 else
458 c -= ('a'-10);
460 lValue <<= 4;
461 lValue += c;
462 break;
465 return lValue;
468 int64 String::ToQuad()
470 enum eType
472 E_Dec = 0,
473 E_Bin,
474 E_Oct,
475 E_Hex
478 char c;
479 int64 lValue = 0;
480 eType lType = E_Dec;
482 for (unsigned int i=0; sContents[i]; i++)
484 if (i >= lLength)
485 break;
486 c = sContents[i];
487 if ((lValue == 0) && (i == 1))
489 if (c == 'x')
490 lType = E_Hex;
491 else if (c == 'b')
492 lType = E_Bin;
493 else
494 lType = E_Oct;
497 switch (lType)
499 case E_Dec:
500 if ((c < '0') || (c > '9'))
501 return lValue;
502 lValue *= 10;
503 lValue += (c-'0');
504 break;
505 case E_Bin:
506 if ((c < '0') || (c > '1'))
507 return lValue;
508 lValue <<= 1;
509 lValue += (c-'0');
510 break;
511 case E_Oct:
512 if ((c < '0') || (c > '7'))
513 return lValue;
514 lValue <<= 3;
515 lValue += (c-'0');
516 break;
517 case E_Hex:
518 if (((c < '0') || (c > '9')) &&
519 ((c < 'a') || (c > 'f')) &&
520 ((c < 'A') || (c > 'F')))
521 return lValue;
523 if (c < '9')
524 c -= '0';
525 else if (c < 'F')
526 c -= ('A'-10);
527 else
528 c -= ('a'-10);
530 lValue <<= 4;
531 lValue += c;
532 break;
535 return lValue;
538 void String::StrLCpy(const char* sSrc, int lNum)
540 if (lNum >= (int)lMaxLen)
541 ReallocBuf(lNum+2);
543 int i = 0;
545 if (sSrc) //
546 { //
547 for (i=0; 0 != sSrc[i]; ++i) // while we have sth to copy
548 { //
549 if (i >= lNum) // that will be tough. STOP ASAP
550 break; //
551 sContents[i] = sSrc[i]; // copy while we have sth to copy
555 while (i < (int)lMaxLen) // ERASE TO THE END
556 { //
557 sContents[i] = 0; //
558 i++; // ...
559 } //
561 Update();
564 void String::BstrCpy(BSTR src)
566 #ifndef __AROS__
567 StrLCpy(&((char*)((int)src<<2))[1], ((char*)((int)src<<2))[0]);
568 #else
569 *this = (char*)src;
570 #endif
573 String &String::Substitute(const char* src, const char* dst)
575 int32 sl = strlen(src);
576 int32 l = 2048;
577 int32 i, p=0;
578 char *d = new char[l];
580 for (i=0; sContents[i] != 0;)
582 if (sContents[i] == src[0])
584 if (strncmp((char*)&sContents[i], src, sl) == 0)
586 for (int j=0; dst[j] != 0; j++)
588 d[p++] = dst[j];
589 if ((p+2) >= l)
591 char *sd = new char[l<<1];
592 memcpy(sd, d, l);
593 l <<= 1;
594 delete [] d;
595 d = sd;
598 i+= sl;
599 continue;
602 d[p++] = sContents[i++];
603 if ((p+2) >= l)
605 char *sd = new char[l<<1];
606 memcpy(sd, d, l);
607 l <<= 1;
608 delete [] d;
609 d = sd;
613 d[p] = 0;
614 Assign(d);
615 delete [] d;
616 return *this;
619 String &String::ToUTF8()
621 char *d = new char[(Length()<<1)+1];
622 int j=0;
624 for (int i=0; ((sContents[i] != 0) && (i<Length())); i++)
626 if (((uint8)sContents[i]) < 0x80)
628 d[j++] = sContents[i];
630 else
632 d[j++] = 0xc0+(sContents[i] >> 6 & 3);
633 d[j++] = 0x80+(sContents[i] & 0x3f);
636 d[j] = 0;
638 Assign(d);
639 delete [] d;
641 return *this;
644 String &String::FromUTF8()
646 char *d = new char[Length()+1];
647 int j=0;
649 for (int i=0; ((sContents[i] != 0) && (i<Length())); i++)
651 if (((uint8)sContents[i]) < 0x80)
653 d[j++] = sContents[i];
655 else if (((uint8)sContents[i]) <0xdf)
657 d[j] = (sContents[i++] & 3) << 6;
658 d[j++] |= (sContents[i] & 0x3f);
660 else
662 d[j++] = '?';
665 d[j] = 0;
667 Assign(d);
668 delete [] d;
670 return *this;
673 // static functions & stuff...
675 void String::strcat(char* pDst, const char* pSrc)
677 if (0 == pDst)
678 return;
679 while (*pDst)
681 pDst++;
683 strcpy(pDst, pSrc);
686 void String::strncat(char* pDst, const char* pSrc, long lLen)
688 if (0 == pDst) // no stirng?
689 return; // abort
690 while (*pDst) //
692 ++pDst; // find end of string
693 --lLen; // and reduce amount of bytes we can take
694 if (0 >= lLen) // if we reached our bottom limit
695 return; // abort.
697 strncpy(pDst, pSrc, lLen); // copy the remaining bytes.
700 VectorT<String> String::Explode()
702 VectorT<String> vec;
703 register int s;
704 register int e;
706 vec.Empty();
708 for (s = 0; s<Length();)
710 register unsigned char c = 0;
713 * skip spaces, tabs, hard spaces
715 while (s<Length())
717 c = sContents[s];
718 if ((c != ' ') &&
719 (c != '\t') &&
720 (c != 0xa0))
721 break;
722 s++;
726 * ignore end of line etc
728 if ((s == Length()) || (c == 10) || (c == 13) || (c == 0))
729 break;
731 e = 0;
733 if (c == '"')
735 s++;
736 while ((s+e) < Length())
738 c = sContents[s+e];
739 if ((c == 10) || (c == 13) || (c == '"') || (c == 0))
740 break;
741 e++;
743 if (c == '"')
745 vec << SubString(s, e);
746 e++;
749 else
751 while ((s+e) < Length())
753 c = sContents[s+e];
754 if ((c == 10) || (c == 13) || (c == ' ') || (c == '\t') || (c == 160) || (c == 0))
755 break;
756 e++;
758 vec << SubString(s, e);
761 s = s+e+1;
764 return vec;
767 String &String::UpperCase()
769 ASSERT(Utility != 0);
770 for (int i=0; i<Length(); i++)
772 sContents[i] = Utility->ToUpper(sContents[i]);
774 Update();
775 return *this;
778 String &String::LowerCase()
780 ASSERT(Utility != 0);
781 for (int i=0; i<Length(); i++)
783 sContents[i] = Utility->ToLower(sContents[i]);
785 Update();
786 return *this;
789 // global operators
791 String GenNS::operator + (const char *sStr1, const String sStr2)
793 String sub(sStr1);
794 sub += sStr2.Data();
795 return sub;