xref: /haiku/src/kits/support/String.cpp (revision 9eb55bc1d104b8fda80898f8b25c94d8000c8255)
1 //------------------------------------------------------------------------------
2 //	Copyright (c) 2001-2003, OpenBeOS
3 //
4 //	Permission is hereby granted, free of charge, to any person obtaining a
5 //	copy of this software and associated documentation files (the "Software"),
6 //	to deal in the Software without restriction, including without limitation
7 //	the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 //	and/or sell copies of the Software, and to permit persons to whom the
9 //	Software is furnished to do so, subject to the following conditions:
10 //
11 //	The above copyright notice and this permission notice shall be included in
12 //	all copies or substantial portions of the Software.
13 //
14 //	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 //	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 //	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 //	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 //	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 //	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 //	DEALINGS IN THE SOFTWARE.
21 //
22 //	File Name:	  String.cpp
23 //	Author(s):    Marc Flerackers (mflerackers@androme.be)
24 //                Stefano Ceccherini (burton666@libero.it)
25 //                Oliver Tappe (openbeos@hirschkaefer.de)
26 //
27 //	Description:   String class supporting common string operations.
28 //------------------------------------------------------------------------------
29 
30 // Standard Includes -----------------------------------------------------------
31 #include <cctype>
32 #include <cstdio>
33 #include <cstdlib>
34 
35 // System Includes -------------------------------------------------------------
36 #include <Debug.h>
37 #include <String.h>
38 
39 // Temporary Includes
40 #include "string_helper.h"
41 
42 #define ENABLE_INLINES 0 // Set this to 1 to make some private methods inline
43 
44 // define proper names for case-option of _DoReplace()
45 #define KEEP_CASE false
46 #define IGNORE_CASE true
47 
48 // define proper names for count-option of _DoReplace()
49 #define REPLACE_ALL 0x7FFFFFFF
50 
51 
52 // helper function, returns minimum of two given values (but clamps to 0):
53 static inline int32
54 min_clamp0(int32 num1, int32 num2)
55 {
56 	if (num1<num2)
57 		return num1 > 0 ? num1 : 0;
58 	else
59 		return num2 > 0 ? num2 : 0;
60 }
61 
62 
63 // helper function, returns length of given string (but clamps to given maximum):
64 static inline int32
65 strlen_clamp(const char* str, int32 max)
66 {	// this should yield 0 for max<0:
67 	int32 len=0;
68 	while( len<max && *str++)
69 		len++;
70 	return len;
71 }
72 
73 
74 // helper function, massages given pointer into a legal c-string:
75 static inline const char *
76 safestr(const char* str)
77 {
78 	return str ? str : "";
79 }
80 
81 
82 // helper class for BString::_ReplaceAtPositions():
83 struct
84 BString::PosVect {
85 	PosVect()
86 		:
87 		size(0),
88 		bufSize(20),
89 		buf(NULL)
90 	{
91 	}
92 
93 	~PosVect()
94 	{
95 		free(buf);
96 	}
97 
98 	bool Add(int32 pos)
99 	{
100 		if (!buf || size == bufSize) {
101 			if (buf)
102 				bufSize *= 2;
103 			int32 *newBuf = (int32 *)realloc(buf, bufSize * sizeof(int32));
104 			if (!newBuf)
105 				return false;
106 			buf = newBuf;
107 		}
108 		buf[size++] = pos;
109 		return true;
110 	}
111 
112 	inline int32 ItemAt(int32 idx) const
113 	{
114 		return buf[idx];
115 	}
116 
117 	inline int32 CountItems() const
118 	{
119 		return size;
120 	}
121 
122 private:
123 	int32 size;
124 	int32 bufSize;
125 	int32 *buf;
126 };
127 
128 
129 // helper macro that is used to fall into debugger if a given param check fails:
130 #ifdef DEBUG
131 	#define CHECK_PARAM( expr, msg) \
132 	if (!(expr)) \
133 		debugger( msg)
134 
135 	#define CHECK_PARAM_RET( expr, msg, retval) \
136 	if (!(expr)) \
137 		debugger( msg)
138 
139 	#define CHECK_PARAM_VOID( expr, msg) \
140 	if (!(expr)) \
141 		debugger( msg)
142 #else
143 	#define CHECK_PARAM( expr, msg) \
144 	if (!(expr)) \
145 		return *this
146 
147 	#define CHECK_PARAM_RET( expr, msg, retval) \
148 	if (!(expr)) \
149 		return (retval);
150 
151 	#define CHECK_PARAM_VOID( expr, msg)
152 #endif
153 
154 // -----------------------------------------------------------------------------
155 
156 /*!
157 	\class BString
158 	\brief String class supporting common string operations
159 
160 	BString is a string allocation and manipulation class. The object
161 	takes care to allocate and free memory for you, so it will always be
162 	"big enough" to store your strings.
163 
164 	\author <a href='mailto:mflerackers@androme.be>Marc Flerackers</a>
165 	\author <a href='mailto:burton666@freemail.it>Stefano Ceccherini</a>
166 	\author <a href='mailto:openbeos@hirschaefer.de>Oliver Tappe</a>
167 */
168 
169 /*!	\var char* BString::_privateData
170 	\brief BString's storage for data
171 */
172 
173 // constructor
174 /*!	\brief Creates an uninitialized BString.
175 */
176 BString::BString()
177 	:_privateData(NULL)
178 {
179 }
180 
181 
182 // constructor
183 /*! \brief Creates a BString and initializes it to the given string.
184 	\param str Pointer to a NULL terminated string.
185 */
186 BString::BString(const char* str)
187 	:_privateData(NULL)
188 {
189 	if (str != NULL)
190 		_Init(str, strlen(str));
191 }
192 
193 
194 // copy constructor
195 /*! \brief Creates a BString and makes it a copy of the supplied one.
196 	\param string the BString object to be copied.
197 */
198 BString::BString(const BString &string)
199 	:_privateData(NULL)
200 {
201 	_Init(string.String(), string.Length());
202 }
203 
204 
205 // constructor
206 /*! \brief Creates a BString and initializes it to the given string.
207 	\param str Pointer to a NULL terminated string.
208 	\param maxLength The amount of characters you want to copy from the original
209 		string.
210 */
211 BString::BString(const char *str, int32 maxLength)
212 	:_privateData(NULL)
213 {
214 	if (str != NULL) {
215 		int32 len = strlen_clamp(str, maxLength);
216 		_Init(str, len);
217 	}
218 }
219 
220 
221 // destructor
222 /*! \brief Frees all resources associated with the object.
223 
224 	Frees the memory allocated by the BString object.
225 */
226 BString::~BString()
227 {
228 	if (_privateData)
229 		free(_privateData - sizeof(int32));
230 }
231 
232 
233 /*---- Access --------------------------------------------------------------*/
234 // String, implemented inline in the header
235 /*! \fn const char* BString::String() const
236 	\brief Returns a pointer to the object string, NULL terminated.
237 
238 	Returns a pointer to the object string, guaranteed to be NULL
239 	terminated. You can't modify or free the pointer. Once the BString
240 	object is deleted, the pointer becomes invalid.
241 
242 	\return A pointer to the object string.
243 */
244 
245 
246 // Length, implemented inline in the header
247 /*!	\fn int32 BString::Length() const
248 	\brief Returns the length of the string, measured in bytes.
249 	\return The length of the string, measured in bytes.
250 */
251 
252 
253 // CountChars
254 /*! \brief Returns the length of the object measured in characters.
255 	\return An integer which is the number of characters in the string.
256 
257 	Counts the number of UTF8 characters contained in the string.
258 */
259 int32
260 BString::CountChars() const
261 {
262 	int32 count = 0;
263 
264 	const char *start = _privateData;
265 
266 	/* String's end. This way we don't have to check for '\0' */
267 	/* but just compare two pointers (which should be faster) */
268 	const char *end = _privateData + Length();
269 
270 #if 0
271 	// ejaesler: Left in memoriam of one man's foolish disregard for the
272 	// maxim "Premature optimization is the root of all evil"
273 	while (*ptr) {
274 		// Jump to next UTF8 character
275 		// ejaesler: BGA's nifty function
276 		ptr += utf8_char_len(*ptr);
277 		count++;
278 	}
279 #endif
280 
281 	while (start++ != end) {
282 		count++;
283 
284 		// Jump to next UTF8 character
285 		for (; (*start & 0xc0) == 0x80; start++);
286 	}
287 
288 	return count;
289 }
290 
291 
292 /*---- Assignment ----------------------------------------------------------*/
293 // equal operator
294 /*! \brief Makes a copy of the given BString object.
295 	\param string The string object to copy.
296 	\return
297 		The function always returns \c *this .
298 */
299 BString&
300 BString::operator=(const BString &string)
301 {
302 	if (&string != this) // Avoid auto-assignment
303 		_DoAssign(string.String(), string.Length());
304 	return *this;
305 }
306 
307 
308 // equal operator
309 /*! \brief Re-initializes the object to the given string.
310 	\param str Pointer to a string.
311 	\return
312 		The function always returns \c *this .
313 */
314 BString&
315 BString::operator=(const char *str)
316 {
317 	if (str != NULL)
318 		_DoAssign(str, strlen(str));
319 	else
320 		_GrowBy(-Length()); // Empties the string
321 
322 	return *this;
323 }
324 
325 
326 // equal operator
327 /*! \brief Re-initializes the object to the given character.
328 	\param c The character which you want to initialize the string to.
329 	\return
330 		The function always returns \c *this .
331 */
332 BString&
333 BString::operator=(char c)
334 {
335 	_DoAssign(&c, 1);
336 	return *this;
337 }
338 
339 
340 // SetTo
341 /*! \brief Re-initializes the object to the given string.
342 	\param str Pointer to a string.
343 	\param length Amount of characters to copy from the original string.
344 	\return
345 		The function always returns \c *this .
346 */
347 BString&
348 BString::SetTo(const char *str, int32 length)
349 {
350 	if (str != NULL) {
351 		int32 len = strlen_clamp(str, length);
352 		_DoAssign(str, len);
353 	}
354 	else
355 		_GrowBy(-Length()); // Empties the string
356 
357 	return *this;
358 }
359 
360 
361 // SetTo
362 /*! \brief Makes a copy of the given BString object.
363 	\param from The string object to copy.
364 	\return
365 		The function always returns \c *this .
366 */
367 BString&
368 BString::SetTo(const BString &from)
369 {
370 	if (&from != this) // Avoid auto-assignment
371 		_DoAssign(from.String(), from.Length());
372 	return *this;
373 }
374 
375 
376 // Adopt
377 /*! \brief Adopt's data of the given BString object, freeing the original object.
378 	\param from The string object to adopt.
379 	\return
380 		The function always returns \c *this .
381 */
382 BString&
383 BString::Adopt(BString &from)
384 {
385 	if (&from == this) // Avoid auto-adoption
386 		return *this;
387 
388 	if (_privateData)
389 		free(_privateData - sizeof(int32));
390 
391 	/* "steal" the data from the given BString */
392 	_privateData = from._privateData;
393 	from._privateData = NULL;
394 
395 	return *this;
396 }
397 
398 
399 // SetTo
400 /*! \brief Makes a copy of the given BString object.
401 	\param from The string object to copy.
402 	\param length Amount of characters to copy from the original BString.
403 	\return
404 		The function always returns \c *this .
405 */
406 BString&
407 BString::SetTo(const BString &string, int32 length)
408 {
409 	if (&string != this) // Avoid auto-assignment
410 		_DoAssign(string.String(), min_clamp0(length, string.Length()));
411 	return *this;
412 }
413 
414 
415 // Adopt
416 /*! \brief Adopt's data of the given BString object, freeing the original object.
417 	\param from The string object to adopt.
418 	\param length Amount of characters to get from the original BString.
419 	\return
420 		The function always returns \c *this .
421 */
422 BString&
423 BString::Adopt(BString &from, int32 length)
424 {
425 	if (&from == this) // Avoid auto-adoption
426 		return *this;
427 
428 	int32 len = min_clamp0(length, from.Length());
429 
430 	if (_privateData)
431 		free(_privateData - sizeof(int32));
432 
433 	/* "steal" the data from the given BString */
434 	_privateData = from._privateData;
435 	from._privateData = NULL;
436 
437 	if (len < Length())
438 		_GrowBy(len - Length()); // Negative, we truncate
439 
440 	return *this;
441 }
442 
443 
444 // SetTo
445 /*! \brief Initializes the object to a string composed by a character you specify.
446 	\param c The character you want to initialize the BString.
447 	\param count The number of characters you want the BString to be composed by.
448 	\return
449 		The function always returns \c *this .
450 */
451 BString&
452 BString::SetTo(char c, int32 count)
453 {
454 	if (count < 0)
455 		count = 0;
456 	int32 curLen = Length();
457 
458 	if (curLen == count || _GrowBy(count - curLen))
459 		memset(_privateData, c, count);
460 	return *this;
461 }
462 
463 
464 /*---- Substring copying ---------------------------------------------------*/
465 
466 // CopyInto
467 /*! \brief Copy the BString data (or part of it) into another BString.
468 	\param into The BString where to copy the object.
469 	\param fromOffset The offset (zero based) where to begin the copy
470 	\param length The amount of bytes to copy.
471 	\return This function always returns *this .
472 */
473 BString &
474 BString::CopyInto(BString &into, int32 fromOffset, int32 length) const
475 {
476 	if (&into != this) {
477 		CHECK_PARAM_RET(fromOffset >= 0, "'fromOffset' must not be negative!",
478 						into);
479 		CHECK_PARAM_RET(fromOffset <= Length(), "'fromOffset' exceeds length!",
480 						into);
481 		into.SetTo(String() + fromOffset, length);
482 	}
483 	return into;
484 }
485 
486 
487 // CopyInto
488 /*! \brief Copy the BString data (or part of it) into the supplied buffer.
489 	\param into The buffer where to copy the object.
490 	\param fromOffset The offset (zero based) where to begin the copy
491 	\param length The amount of bytes to copy.
492 */
493 void
494 BString::CopyInto(char *into, int32 fromOffset, int32 length) const
495 {
496 	if (into != NULL) {
497 		CHECK_PARAM_VOID(fromOffset >= 0, "'fromOffset' must not be negative!");
498 		CHECK_PARAM_VOID(fromOffset <= Length(), "'fromOffset' exceeds length!");
499 		int32 len = min_clamp0(length, Length() - fromOffset);
500 		memcpy(into, _privateData + fromOffset, len);
501 	}
502 }
503 
504 
505 /*---- Appending -----------------------------------------------------------*/
506 // plus operator
507 /*!	\brief Appends the given string to the object.
508 	\param str A pointer to the string to append.
509 	\return This function always returns *this .
510 */
511 BString&
512 BString::operator+=(const char *str)
513 {
514 	if (str != NULL)
515 		_DoAppend(str, strlen(str));
516 	return *this;
517 }
518 
519 
520 // plus operator
521 /*!	\brief Appends the given character to the object.
522 	\param c The character to append.
523 	\return This function always returns *this .
524 */
525 BString&
526 BString::operator+=(char c)
527 {
528 	_DoAppend(&c, 1);
529 	return *this;
530 }
531 
532 
533 // Append
534 /*!	\brief Appends the given BString to the object.
535 	\param string The BString to append.
536 	\param length The maximum bytes to get from the original object.
537 	\return This function always returns *this .
538 */
539 BString&
540 BString::Append(const BString &string, int32 length)
541 {
542 	_DoAppend(string.String(), min_clamp0(length, string.Length()));
543 	return *this;
544 }
545 
546 
547 // Append
548 /*!	\brief Appends the given string to the object.
549 	\param str A pointer to the string to append.
550 	\param length The maximum bytes to get from the original string.
551 	\return This function always returns *this .
552 */
553 BString&
554 BString::Append(const char *str, int32 length)
555 {
556 	if (str != NULL) {
557 		int32 len = strlen_clamp(str, length);
558 		_DoAppend(str, len);
559 	}
560 	return *this;
561 }
562 
563 
564 // Append
565 /*!	\brief Appends the given character to the object.
566 	\param c The character to append.
567 	\param count The number of characters to append.
568 	\return This function always returns *this .
569 */
570 BString&
571 BString::Append(char c, int32 count)
572 {
573 	int32 len = Length();
574 	if (count > 0 && _GrowBy(count))
575 		memset(_privateData + len, c, count);
576 
577 	return *this;
578 }
579 
580 
581 /*---- Prepending ----------------------------------------------------------*/
582 // Prepend
583 /*!	\brief Prepends the given string to the object.
584 	\param str A pointer to the string to prepend.
585 	\return This function always returns *this .
586 */
587 BString&
588 BString::Prepend(const char *str)
589 {
590 	if (str != NULL)
591 		_DoPrepend(str, strlen(str));
592 	return *this;
593 }
594 
595 
596 // Prepend
597 /*!	\brief Prepends the given BString to the object.
598 	\param string The BString object to prepend.
599 	\return This function always returns *this .
600 */
601 BString&
602 BString::Prepend(const BString &string)
603 {
604 	if (&string != this)
605 		_DoPrepend(string.String(), string.Length());
606 	return *this;
607 }
608 
609 
610 // Prepend
611 /*!	\brief Prepends the given string to the object.
612 	\param str A pointer to the string to prepend.
613 	\param length The maximum amount of bytes to get from the string.
614 	\return This function always returns *this .
615 */
616 BString&
617 BString::Prepend(const char *str, int32 length)
618 {
619 	if (str != NULL) {
620 		int32 len = strlen_clamp(str, length);
621 		_DoPrepend(str, len);
622 	}
623 	return *this;
624 }
625 
626 
627 // Prepend
628 /*!	\brief Prepends the given BString to the object.
629 	\param string The BString object to prepend.
630 	\param len The maximum amount of bytes to get from the BString.
631 	\return This function always returns *this .
632 */
633 BString&
634 BString::Prepend(const BString &string, int32 len)
635 {
636 	if (&string != this)
637 		_DoPrepend(string.String(), min_clamp0(len, string.Length()));
638 	return *this;
639 }
640 
641 
642 // Prepend
643 /*!	\brief Prepends the given character to the object.
644 	\param c The character to prepend.
645 	\param count The amount of characters to prepend.
646 	\return This function always returns *this .
647 */
648 BString&
649 BString::Prepend(char c, int32 count)
650 {
651 	if (count > 0 && _OpenAtBy(0, count))
652 		memset(_privateData, c, count);
653 
654 	return *this;
655 }
656 
657 
658 /*---- Inserting ----------------------------------------------------------*/
659 // Insert
660 /*! \brief Inserts the given string at the given position into the object's data.
661 	\param str A pointer to the string to insert.
662 	\param pos The offset into the BString's data where to insert the string.
663 	\return This function always returns *this .
664 */
665 BString&
666 BString::Insert(const char *str, int32 pos)
667 {
668 	if (str != NULL) {
669 		CHECK_PARAM(pos <= Length(), "'pos' exceeds length!");
670 		int32 len = (int32)strlen(str);
671 		if (pos < 0) {
672 			int32 skipLen = min_clamp0(-1 * pos, len);
673 			str += skipLen;
674 			len -= skipLen;
675 			pos = 0;
676 		} else
677 			pos = min_clamp0(pos, Length());
678 		if (_OpenAtBy(pos, len))
679 			memcpy(_privateData + pos, str, len);
680 	}
681 	return *this;
682 }
683 
684 
685 // Insert
686 /*! \brief Inserts the given string at the given position into the object's data.
687 	\param str A pointer to the string to insert.
688 	\param length The amount of bytes to insert.
689 	\param pos The offset into the BString's data where to insert the string.
690 	\return This function always returns *this .
691 */
692 BString&
693 BString::Insert(const char *str, int32 length, int32 pos)
694 {
695 	if (str != NULL) {
696 		CHECK_PARAM(pos <= Length(), "'pos' exceeds length!");
697 		int32 len = strlen_clamp(str, length);
698 		if (pos < 0) {
699 			int32 skipLen = min_clamp0(-1 * pos, len);
700 			str += skipLen;
701 			len -= skipLen;
702 			pos = 0;
703 		} else
704 			pos = min_clamp0(pos, Length());
705 		if (_OpenAtBy(pos, len))
706 			memcpy(_privateData + pos, str, len);
707 	}
708 	return *this;
709 }
710 
711 
712 // Insert
713 /*! \brief Inserts the given string at the given position into the object's data.
714 	\param str A pointer to the string to insert.
715 	\param fromOffset
716 	\param length The amount of bytes to insert.
717 	\param pos The offset into the BString's data where to insert the string.
718 	\return This function always returns *this .
719 */
720 BString&
721 BString::Insert(const char *str, int32 fromOffset, int32 length, int32 pos)
722 {
723 	CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!");
724 	return Insert(str + fromOffset, length, pos);
725 }
726 
727 
728 // Insert
729 /*! \brief Inserts the given BString at the given position into the object's data.
730 	\param string The BString object to insert.
731 	\param pos The offset into the BString's data where to insert the string.
732 	\return This function always returns *this .
733 */
734 BString&
735 BString::Insert(const BString &string, int32 pos)
736 {
737 	if (&string != this)
738 		Insert(string.String(), pos); //TODO: Optimize
739 	return *this;
740 }
741 
742 
743 // Insert
744 /*! \brief Inserts the given BString at the given position into the object's data.
745 	\param string The BString object to insert.
746 	\param length The amount of bytes to insert.
747 	\param pos The offset into the BString's data where to insert the string.
748 	\return This function always returns *this .
749 */
750 BString&
751 BString::Insert(const BString &string, int32 length, int32 pos)
752 {
753 	if (&string != this)
754 		Insert(string.String(), length, pos); //TODO: Optimize
755 	return *this;
756 }
757 
758 
759 // Insert
760 /*! \brief Inserts the given string at the given position into the object's data.
761 	\param string The BString object to insert.
762 	\param fromOffset
763 	\param length The amount of bytes to insert.
764 	\param pos The offset into the BString's data where to insert the string.
765 	\return This function always returns *this .
766 */
767 BString&
768 BString::Insert(const BString &string, int32 fromOffset, int32 length, int32 pos)
769 {
770 	if (&string != this) {
771 		CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!");
772 		Insert(string.String() + fromOffset, length, pos);
773 	}
774 	return *this;
775 }
776 
777 
778 // Insert
779 /*! \brief Inserts the given character at the given position into the object's data.
780 	\param c The character to insert.
781 	\param count The amount of bytes to insert.
782 	\param pos The offset into the BString's data where to insert the string.
783 	\return This function always returns *this .
784 */
785 BString&
786 BString::Insert(char c, int32 count, int32 pos)
787 {
788 	CHECK_PARAM(pos <= Length(), "'pos' exceeds length!");
789 	if (pos < 0) {
790 		count = max_c(count + pos, 0);
791 		pos = 0;
792 	} else
793 		pos = min_clamp0(pos, Length());
794 
795 	if (count > 0 && _OpenAtBy(pos, count))
796 		memset(_privateData + pos, c, count);
797 
798 	return *this;
799 }
800 
801 
802 /*---- Removing -----------------------------------------------------------*/
803 // Truncate
804 /*! \brief Truncate the string to the new length.
805 	\param newLength The new lenght of the string.
806 	\param lazy If true, the memory-optimisation is postponed to later
807 	\return This function always returns *this .
808 */
809 BString&
810 BString::Truncate(int32 newLength, bool lazy)
811 {
812 	if (newLength < 0)
813 		newLength = 0;
814 
815 	int32 curLen = Length();
816 
817 	if (newLength < curLen) {
818 		if (lazy) {
819 			// don't free memory yet, just set new length:
820 			// XXX: Uhm, where do we keep track of the amount
821 			// of memory we allocated ?
822 			_SetLength(newLength);
823 			_privateData[newLength] = '\0';
824 		} else
825 			_GrowBy(newLength - curLen); //Negative
826 	}
827 	return *this;
828 }
829 
830 
831 // Remove
832 /*! \brief Removes some bytes, starting at the given offset
833 	\param from The offset from which you want to start removing
834 	\param length The number of bytes to remove
835 	\return This function always returns *this .
836 */
837 BString&
838 BString::Remove(int32 from, int32 length)
839 {
840 	int32 len = Length();
841 	if (from < 0) {
842 		int32 skipLen = min_clamp0(from, len);
843 		len -= skipLen;
844 		from = 0;
845 	} else
846 		from = min_clamp0(from, len);
847 	_ShrinkAtBy(from, min_clamp0(length, len - from));
848 	return *this;
849 }
850 
851 
852 // Remove
853 /*! \brief Removes the first occurrence of the given BString.
854 	\param string The BString to remove.
855 	\return This function always returns *this .
856 */
857 BString&
858 BString::RemoveFirst(const BString &string)
859 {
860 	int32 pos = _ShortFindAfter(string.String(), string.Length());
861 
862 	if (pos >= 0)
863 		_ShrinkAtBy(pos, string.Length());
864 
865 	return *this;
866 }
867 
868 
869 // Remove
870 /*! \brief Removes the last occurrence of the given BString.
871 	\param string The BString to remove.
872 	\return This function always returns *this .
873 */
874 BString&
875 BString::RemoveLast(const BString &string)
876 {
877 	int32 pos = _FindBefore(string.String(), Length(), string.Length());
878 
879 	if (pos >= 0)
880 		_ShrinkAtBy(pos, string.Length());
881 
882 	return *this;
883 }
884 
885 
886 // Remove
887 /*! \brief Removes all occurrences of the given BString.
888 	\param string The BString to remove.
889 	\return This function always returns *this .
890 */
891 BString&
892 BString::RemoveAll(const BString &string)
893 {
894 	return _DoReplace(string.String(), "", REPLACE_ALL, 0, KEEP_CASE);
895 }
896 
897 
898 // Remove
899 /*! \brief Removes the first occurrence of the given string.
900 	\param str A pointer to the string to remove.
901 	\return This function always returns *this .
902 */
903 BString&
904 BString::RemoveFirst(const char *str)
905 {
906 	if (str != NULL) {
907 		int32 pos = _ShortFindAfter(str, strlen(str));
908 		if (pos >= 0)
909 			_ShrinkAtBy(pos, strlen(str));
910 	}
911 	return *this;
912 }
913 
914 
915 // Remove
916 /*! \brief Removes the last occurrence of the given string.
917 	\param str A pointer to the string to remove.
918 	\return This function always returns *this .
919 */
920 BString&
921 BString::RemoveLast(const char *str)
922 {
923 	if (str != NULL) {
924 		int32 len = strlen(str);
925 		int32 pos = _FindBefore(str, Length(), len);
926 		if (pos >= 0)
927 			_ShrinkAtBy(pos, len);
928 	}
929 	return *this;
930 }
931 
932 
933 // Remove
934 /*! \brief Removes all occurrences of the given string.
935 	\param str A pointer to the string to remove.
936 	\return This function always returns *this .
937 */
938 BString&
939 BString::RemoveAll(const char *str)
940 {
941 	return _DoReplace(str, "", REPLACE_ALL, 0, KEEP_CASE);
942 }
943 
944 
945 // Remove
946 /*! \brief Removes all the characters specified.
947 	\param setOfCharsToRemove The set of characters to remove.
948 	\return This function always returns *this .
949 */
950 BString&
951 BString::RemoveSet(const char *setOfCharsToRemove)
952 {
953 	return ReplaceSet(setOfCharsToRemove, "");
954 }
955 
956 
957 // MoveInto
958 /*! \brief Move the BString data (or part of it) into another BString.
959 	\param into The BString where to move the object.
960 	\param from The offset (zero based) where to begin the move
961 	\param length The amount of bytes to move.
962 	\return This function always returns into.
963 */
964 BString&
965 BString::MoveInto(BString &into, int32 from, int32 length)
966 {
967 	CHECK_PARAM_RET(from >= 0, "'from' must not be negative!", into);
968 	CHECK_PARAM_RET(from <= Length(), "'from' exceeds length!", into);
969 	int32 len = min_clamp0(length, Length() - from);
970 	if (&into == this) {
971 		/* TODO: [zooey]: to be activated later (>R1):
972 		// strings are identical, just move the data:
973 		if (from>0 && _privateData)
974 			memmove( _privateData, _privateData+from, len);
975 		Truncate( len);
976 		*/
977 		return *this;
978 	}
979 	into.SetTo(String() + from, len);
980 	_ShrinkAtBy(from, len);
981 
982 	return into;
983 }
984 
985 
986 // MoveInto
987 /*! \brief Move the BString data (or part of it) into the given buffer.
988 	\param into The buffer where to move the object.
989 	\param from The offset (zero based) where to begin the move
990 	\param length The amount of bytes to move.
991 */
992 void
993 BString::MoveInto(char *into, int32 from, int32 length)
994 {
995 	if (into != NULL) {
996 		CHECK_PARAM_VOID(from >= 0, "'from' must not be negative!");
997 		CHECK_PARAM_VOID(from <= Length(), "'from' exceeds length!");
998 		int32 len = min_clamp0(length, Length() - from);
999 		memcpy(into, String() + from, len);
1000 		into[len] = '\0';
1001 		_ShrinkAtBy(from, len);
1002 	}
1003 }
1004 
1005 
1006 /*---- Compare functions ---------------------------------------------------*/
1007 bool
1008 BString::operator<(const char *string) const
1009 {
1010 	return strcmp(String(), safestr(string)) < 0;
1011 }
1012 
1013 
1014 bool
1015 BString::operator<=(const char *string) const
1016 {
1017 	return strcmp(String(), safestr(string)) <= 0;
1018 }
1019 
1020 
1021 bool
1022 BString::operator==(const char *string) const
1023 {
1024 	return strcmp(String(), safestr(string)) == 0;
1025 }
1026 
1027 
1028 bool
1029 BString::operator>=(const char *string) const
1030 {
1031 	return strcmp(String(), safestr(string)) >= 0;
1032 }
1033 
1034 
1035 bool
1036 BString::operator>(const char *string) const
1037 {
1038 	return strcmp(String(), safestr(string)) > 0;
1039 }
1040 
1041 
1042 /*---- strcmp-style compare functions --------------------------------------*/
1043 int
1044 BString::Compare(const BString &string) const
1045 {
1046 	return strcmp(String(), string.String());
1047 }
1048 
1049 
1050 int
1051 BString::Compare(const char *string) const
1052 {
1053 	return strcmp(String(), safestr(string));
1054 }
1055 
1056 
1057 int
1058 BString::Compare(const BString &string, int32 n) const
1059 {
1060 	return strncmp(String(), string.String(), n);
1061 }
1062 
1063 
1064 int
1065 BString::Compare(const char *string, int32 n) const
1066 {
1067 	return strncmp(String(), safestr(string), n);
1068 }
1069 
1070 
1071 int
1072 BString::ICompare(const BString &string) const
1073 {
1074 	return strcasecmp(String(), string.String());
1075 }
1076 
1077 
1078 int
1079 BString::ICompare(const char *str) const
1080 {
1081 	return strcasecmp(String(), safestr(str));
1082 }
1083 
1084 
1085 int
1086 BString::ICompare(const BString &string, int32 n) const
1087 {
1088 	return strncasecmp(String(), string.String(), n);
1089 }
1090 
1091 
1092 int
1093 BString::ICompare(const char *str, int32 n) const
1094 {
1095 	return strncasecmp(String(), safestr(str), n);
1096 }
1097 
1098 
1099 /*---- Searching -----------------------------------------------------------*/
1100 // FindFirst
1101 /*! \brief Find the first occurrence of the given BString.
1102 	\param string The BString to search for.
1103 	\return The offset(zero based) into the data
1104 		where the given BString has been found.
1105 */
1106 int32
1107 BString::FindFirst(const BString &string) const
1108 {
1109 	return _ShortFindAfter(string.String(), string.Length());
1110 }
1111 
1112 
1113 // FindFirst
1114 /*! \brief Find the first occurrence of the given string.
1115 	\param string The string to search for.
1116 	\return The offset(zero based) into the data
1117 		where the given string has been found.
1118 */
1119 int32
1120 BString::FindFirst(const char *string) const
1121 {
1122 	if (string == NULL)
1123 		return B_BAD_VALUE;
1124 	return _ShortFindAfter(string, strlen(string));
1125 }
1126 
1127 
1128 // FindFirst
1129 /*! \brief Find the first occurrence of the given BString,
1130 		starting from the given offset.
1131 	\param string The BString to search for.
1132 	\param fromOffset The offset where to start the search.
1133 	\return An integer which is the offset(zero based) into the data
1134 		where the given BString has been found.
1135 */
1136 int32
1137 BString::FindFirst(const BString &string, int32 fromOffset) const
1138 {
1139 	if (fromOffset < 0)
1140 		return B_ERROR;
1141 	return _FindAfter(string.String(), min_clamp0(fromOffset, Length()),
1142 						    string.Length());
1143 }
1144 
1145 
1146 // FindFirst
1147 /*! \brief Find the first occurrence of the given string,
1148 		starting from the given offset.
1149 	\param string The string to search for.
1150 	\param fromOffset The offset where to start the search.
1151 	\return The offset(zero based) into the data
1152 		where the given string has been found.
1153 */
1154 int32
1155 BString::FindFirst(const char *string, int32 fromOffset) const
1156 {
1157 	if (string == NULL)
1158 		return B_BAD_VALUE;
1159 	if (fromOffset < 0)
1160 		return B_ERROR;
1161 	return _FindAfter(string, min_clamp0(fromOffset, Length()), strlen(string));
1162 }
1163 
1164 
1165 // FindFirst
1166 /*! \brief Find the first occurrence of the given character.
1167 	\param c The character to search for.
1168 	\return The offset(zero based) into the data
1169 		where the given character has been found.
1170 */
1171 int32
1172 BString::FindFirst(char c) const
1173 {
1174 	const char *start = String();
1175 	const char *end = String() + Length(); /* String's end */
1176 
1177 	/* Scans the string until we find the character, */
1178 	/* or we hit the string's end */
1179 	while(start != end && *start != c)
1180 		start++;
1181 
1182 	if (start == end)
1183 		return B_ERROR;
1184 
1185 	return start - String();
1186 }
1187 
1188 
1189 // FindFirst
1190 /*! \brief Find the first occurrence of the given character,
1191 		starting from the given offset.
1192 	\param c The character to search for.
1193 	\param fromOffset The offset where to start the search.
1194 	\return The offset(zero based) into the data
1195 		where the given character has been found.
1196 */
1197 int32
1198 BString::FindFirst(char c, int32 fromOffset) const
1199 {
1200 	if (fromOffset < 0)
1201 		return B_ERROR;
1202 
1203 	const char *start = String() + min_clamp0(fromOffset, Length());
1204 	const char *end = String() + Length(); /* String's end */
1205 
1206 	/* Scans the string until we found the character, */
1207 	/* or we hit the string's end */
1208 	while(start < end && *start != c)
1209 		start++;
1210 
1211 	if (start >= end)
1212 		return B_ERROR;
1213 
1214 	return start - String();
1215 }
1216 
1217 
1218 // FindLast
1219 /*! \brief Find the last occurrence of the given BString.
1220 	\param string The BString to search for.
1221 	\return The offset(zero based) into the data
1222 		where the given BString has been found.
1223 */
1224 int32
1225 BString::FindLast(const BString &string) const
1226 {
1227 	return _FindBefore(string.String(), Length(), string.Length());
1228 }
1229 
1230 
1231 // FindLast
1232 /*! \brief Find the last occurrence of the given string.
1233 	\param string The string to search for.
1234 	\return The offset(zero based) into the data
1235 		where the given string has been found.
1236 */
1237 int32
1238 BString::FindLast(const char *string) const
1239 {
1240 	if (string == NULL)
1241 		return B_BAD_VALUE;
1242 	return _FindBefore(string, Length(), strlen(string));
1243 }
1244 
1245 
1246 // FindLast
1247 /*! \brief Find the last occurrence of the given BString,
1248 		starting from the given offset, and going backwards.
1249 	\param string The BString to search for.
1250 	\param beforeOffset The offset where to start the search.
1251 	\return An integer which is the offset(zero based) into the data
1252 		where the given BString has been found.
1253 */
1254 int32
1255 BString::FindLast(const BString &string, int32 beforeOffset) const
1256 {
1257 	if (beforeOffset < 0)
1258 		return B_ERROR;
1259 	return _FindBefore(string.String(), min_clamp0(beforeOffset, Length()),
1260 							 string.Length());
1261 }
1262 
1263 
1264 // FindLast
1265 /*! \brief Find the last occurrence of the given string,
1266 		starting from the given offset, and going backwards.
1267 	\param string The string to search for.
1268 	\return The offset(zero based) into the data
1269 		where the given string has been found.
1270 */
1271 int32
1272 BString::FindLast(const char *string, int32 beforeOffset) const
1273 {
1274 	if (string == NULL)
1275 		return B_BAD_VALUE;
1276 	if (beforeOffset < 0)
1277 		return B_ERROR;
1278 	return _FindBefore(string, min_clamp0(beforeOffset, Length()), strlen(string));
1279 }
1280 
1281 
1282 // FindLast
1283 /*! \brief Find the last occurrence of the given character.
1284 	\param c The character to search for.
1285 	\return The offset(zero based) into the data
1286 		where the given character has been found.
1287 */
1288 int32
1289 BString::FindLast(char c) const
1290 {
1291 	const char *start = String();
1292 	const char *end = String() + Length(); /* String's end */
1293 
1294 	/* Scans the string backwards until we found the character, */
1295 	/* or we reach the string's start */
1296 	while(end != start && *end != c)
1297 		end--;
1298 
1299 	if (end == start)
1300 		return B_ERROR;
1301 
1302 	return end - String();
1303 }
1304 
1305 
1306 // FindLast
1307 /*! \brief Find the last occurrence of the given character,
1308 		starting from the given offset and going backwards.
1309 	\param c The character to search for.
1310 	\param beforeOffset The offset where to start the search.
1311 	\return The offset(zero based) into the data
1312 		where the given character has been found.
1313 */
1314 int32
1315 BString::FindLast(char c, int32 beforeOffset) const
1316 {
1317 	if (beforeOffset < 0)
1318 		return B_ERROR;
1319 
1320 	const char *start = String();
1321 	const char *end = String() + Length() - beforeOffset;
1322 
1323 	/* Scans the string backwards until we found the character, */
1324 	/* or we reach the string's start */
1325 	while(end > start && *end != c)
1326 		end--;
1327 
1328 	if (end <= start)
1329 		return B_ERROR;
1330 
1331 	return end - String();
1332 }
1333 
1334 
1335 int32
1336 BString::IFindFirst(const BString &string) const
1337 {
1338 	return _IFindAfter(string.String(), 0, string.Length());
1339 }
1340 
1341 
1342 int32
1343 BString::IFindFirst(const char *string) const
1344 {
1345 	if (string == NULL)
1346 		return B_BAD_VALUE;
1347 	return _IFindAfter(string, 0, strlen(string));
1348 }
1349 
1350 
1351 int32
1352 BString::IFindFirst(const BString &string, int32 fromOffset) const
1353 {
1354 	if (fromOffset < 0)
1355 		return B_ERROR;
1356 	return _IFindAfter(string.String(), min_clamp0(fromOffset, Length()),
1357 						    string.Length());
1358 }
1359 
1360 
1361 int32
1362 BString::IFindFirst(const char *string, int32 fromOffset) const
1363 {
1364 	if (string == NULL)
1365 		return B_BAD_VALUE;
1366 	if (fromOffset < 0)
1367 		return B_ERROR;
1368 	return _IFindAfter(string, min_clamp0(fromOffset,Length()), strlen(string));
1369 }
1370 
1371 
1372 int32
1373 BString::IFindLast(const BString &string) const
1374 {
1375 	return _IFindBefore(string.String(), Length(), string.Length());
1376 }
1377 
1378 
1379 int32
1380 BString::IFindLast(const char *string) const
1381 {
1382 	if (string == NULL)
1383 		return B_BAD_VALUE;
1384 	return _IFindBefore(string, Length(), strlen(string));
1385 }
1386 
1387 
1388 int32
1389 BString::IFindLast(const BString &string, int32 beforeOffset) const
1390 {
1391 	if (beforeOffset < 0)
1392 		return B_ERROR;
1393 	return _IFindBefore(string.String(), min_clamp0(beforeOffset, Length()),
1394 							  string.Length());
1395 }
1396 
1397 
1398 int32
1399 BString::IFindLast(const char *string, int32 beforeOffset) const
1400 {
1401 	if (string == NULL)
1402 		return B_BAD_VALUE;
1403 	if (beforeOffset < 0)
1404 		return B_ERROR;
1405 	return _IFindBefore(string, min_clamp0(beforeOffset,Length()),
1406 							  strlen(string));
1407 }
1408 
1409 
1410 /*---- Replacing -----------------------------------------------------------*/
1411 BString&
1412 BString::ReplaceFirst(char replaceThis, char withThis)
1413 {
1414 	int32 pos = FindFirst(replaceThis);
1415 
1416 	if (pos >= 0)
1417 		_privateData[pos] = withThis;
1418 
1419 	return *this;
1420 }
1421 
1422 
1423 BString&
1424 BString::ReplaceLast(char replaceThis, char withThis)
1425 {
1426 	int32 pos = FindLast(replaceThis);
1427 
1428 	if (pos >= 0)
1429 		_privateData[pos] = withThis;
1430 
1431 	return *this;
1432 }
1433 
1434 
1435 BString&
1436 BString::ReplaceAll(char replaceThis, char withThis, int32 fromOffset)
1437 {
1438 	CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!");
1439 	for (int32 pos = min_clamp0(fromOffset, Length());;) {
1440 		pos = FindFirst(replaceThis, pos);
1441 		if (pos < 0)
1442 			break;
1443 		_privateData[pos] = withThis;
1444 	}
1445 
1446 	return *this;
1447 }
1448 
1449 
1450 BString&
1451 BString::Replace(char replaceThis, char withThis, int32 maxReplaceCount, int32 fromOffset)
1452 {
1453 	CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!");
1454 	if (maxReplaceCount > 0) {
1455 		for (int32 pos = min_clamp0(fromOffset, Length());
1456 			  		maxReplaceCount > 0; maxReplaceCount--) {
1457 			pos = FindFirst(replaceThis, pos);
1458 			if (pos < 0)
1459 				break;
1460 			_privateData[pos] = withThis;
1461 		}
1462 	}
1463 	return *this;
1464 }
1465 
1466 
1467 BString&
1468 BString::ReplaceFirst(const char *replaceThis, const char *withThis)
1469 {
1470 	return _DoReplace( replaceThis, withThis, 1, 0, KEEP_CASE);
1471 }
1472 
1473 
1474 BString&
1475 BString::ReplaceLast(const char *replaceThis, const char *withThis)
1476 {
1477 	if (replaceThis == NULL)
1478 		return *this;
1479 
1480 	int32 firstStringLength = strlen(replaceThis);
1481 	int32 pos = _FindBefore(replaceThis, Length(), firstStringLength);
1482 
1483 	if (pos >= 0) {
1484 		int32 len = (withThis ? strlen(withThis) : 0);
1485 		int32 difference = len - firstStringLength;
1486 
1487 		if (difference > 0) {
1488 			if (!_OpenAtBy(pos, difference))
1489 				return *this;
1490 		} else if (difference < 0) {
1491 			if (!_ShrinkAtBy(pos, -difference))
1492 				return *this;
1493 		}
1494 		memcpy(_privateData + pos, withThis, len);
1495 	}
1496 
1497 	return *this;
1498 }
1499 
1500 
1501 BString&
1502 BString::ReplaceAll(const char *replaceThis, const char *withThis, int32 fromOffset)
1503 {
1504 	CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!");
1505 	return _DoReplace(replaceThis, withThis, REPLACE_ALL,
1506 							 min_clamp0(fromOffset,Length()), KEEP_CASE);
1507 }
1508 
1509 
1510 BString&
1511 BString::Replace(const char *replaceThis, const char *withThis, int32 maxReplaceCount, int32 fromOffset)
1512 {
1513 	CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!");
1514 	return _DoReplace(replaceThis, withThis, maxReplaceCount,
1515 							 min_clamp0(fromOffset,Length()), KEEP_CASE);
1516 }
1517 
1518 
1519 BString&
1520 BString::IReplaceFirst(char replaceThis, char withThis)
1521 {
1522 	char tmp[2] = { replaceThis, '\0' };
1523 	int32 pos = _IFindAfter(tmp, 0, 1);
1524 
1525 	if (pos >= 0)
1526 		_privateData[pos] = withThis;
1527 
1528 	return *this;
1529 }
1530 
1531 
1532 BString&
1533 BString::IReplaceLast(char replaceThis, char withThis)
1534 {
1535 	char tmp[2] = { replaceThis, '\0' };
1536 	int32 pos = _IFindBefore(tmp, Length(), 1);
1537 
1538 	if (pos >= 0)
1539 		_privateData[pos] = withThis;
1540 
1541 	return *this;
1542 }
1543 
1544 
1545 BString&
1546 BString::IReplaceAll(char replaceThis, char withThis, int32 fromOffset)
1547 {
1548 	CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!");
1549 
1550 	char tmp[2] = { replaceThis, '\0' };
1551 
1552 	for (int32 pos = min_clamp0(fromOffset, Length());;) {
1553 		pos = _IFindAfter(tmp, pos, 1);
1554 		if (pos < 0)
1555 			break;
1556 		_privateData[pos] = withThis;
1557 	}
1558 	return *this;
1559 }
1560 
1561 
1562 BString&
1563 BString::IReplace(char replaceThis, char withThis, int32 maxReplaceCount, int32 fromOffset)
1564 {
1565 	CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!");
1566 
1567 	char tmp[2] = { replaceThis, '\0' };
1568 
1569 	if (_privateData == NULL)
1570 		return *this;
1571 
1572 	for (int32 pos = min_clamp0(fromOffset,Length());
1573 		  	maxReplaceCount > 0;   maxReplaceCount--) {
1574 		pos = _IFindAfter(tmp, pos, 1);
1575 		if (pos < 0)
1576 			break;
1577 		_privateData[pos] = withThis;
1578 	}
1579 	return *this;
1580 }
1581 
1582 
1583 BString&
1584 BString::IReplaceFirst(const char *replaceThis, const char *withThis)
1585 {
1586 	return _DoReplace(replaceThis, withThis, 1, 0, IGNORE_CASE);
1587 }
1588 
1589 
1590 BString&
1591 BString::IReplaceLast(const char *replaceThis, const char *withThis)
1592 {
1593 	if (replaceThis == NULL)
1594 		return *this;
1595 
1596 	int32 firstStringLength = strlen(replaceThis);
1597 	int32 pos = _IFindBefore(replaceThis, Length(), firstStringLength);
1598 
1599 	if (pos >= 0) {
1600 		int32 len = (withThis ? strlen(withThis) : 0);
1601 		int32 difference = len - firstStringLength;
1602 
1603 		if (difference > 0) {
1604 			if (!_OpenAtBy(pos, difference))
1605 				return *this;
1606 		} else if (difference < 0) {
1607 			if (!_ShrinkAtBy(pos, -difference))
1608 				return *this;
1609 		}
1610 		memcpy(_privateData + pos, withThis, len);
1611 
1612 	}
1613 
1614 	return *this;
1615 }
1616 
1617 
1618 BString&
1619 BString::IReplaceAll(const char *replaceThis, const char *withThis, int32 fromOffset)
1620 {
1621 	CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!");
1622 	return _DoReplace(replaceThis, withThis, REPLACE_ALL,
1623 							 min_clamp0(fromOffset, Length()), IGNORE_CASE);
1624 }
1625 
1626 
1627 BString&
1628 BString::IReplace(const char *replaceThis, const char *withThis, int32 maxReplaceCount, int32 fromOffset)
1629 {
1630 	CHECK_PARAM(fromOffset >= 0, "'fromOffset' must not be negative!");
1631 	return _DoReplace(replaceThis, withThis, maxReplaceCount,
1632 							 min_clamp0(fromOffset, Length()), IGNORE_CASE);
1633 }
1634 
1635 
1636 BString&
1637 BString::ReplaceSet(const char *setOfChars, char with)
1638 {
1639 	if (setOfChars == NULL)
1640 		return *this;
1641 
1642 	int32 offset = 0;
1643 	int32 length = Length();
1644 
1645 	for (int32 pos;;) {
1646 		pos = strcspn(String() + offset, setOfChars);
1647 
1648 		offset += pos;
1649 		if (offset >= length)
1650 			break;
1651 
1652 		_privateData[offset] = with;
1653 		offset++;
1654 	}
1655 
1656 	return *this;
1657 }
1658 
1659 BString&
1660 BString::ReplaceSet(const char *setOfChars, const char *with)
1661 {
1662 	int32 withLen = with ? strlen(with) : 0;
1663 	if (withLen == 1)
1664 		// delegate simple case:
1665 		return ReplaceSet( setOfChars, *with);
1666 
1667 	if (setOfChars == NULL || _privateData == NULL)
1668 		return *this;
1669 
1670 	PosVect positions;
1671 
1672 	int32 searchLen = 1;
1673 	int32 len = Length();
1674 	int32 pos = 0;
1675 	for (int32 offset = 0; offset < len; offset += (pos+searchLen))
1676 	{
1677 		pos = strcspn(_privateData + offset, setOfChars);
1678 		if (pos + offset >= len)
1679 			break;
1680 		if (!positions.Add(offset + pos))
1681 			return *this;
1682 	}
1683 
1684 	_ReplaceAtPositions(&positions, searchLen, with, withLen);
1685 	return *this;
1686 }
1687 
1688 
1689 /*---- Unchecked char access -----------------------------------------------*/
1690 
1691 // operator[]
1692 /*! \brief Returns a reference to the data at the given offset.
1693 
1694 	This function can be used to read a byte or to change its value.
1695 	\param index The index (zero based) of the byte to get.
1696 	\return Returns a reference to the specified byte.
1697 */
1698 char &
1699 BString::operator[](int32 index)
1700 {
1701 	return _privateData[index];
1702 }
1703 
1704 
1705 /*---- Fast low-level manipulation -----------------------------------------*/
1706 char*
1707 BString::LockBuffer(int32 maxLength)
1708 {
1709 	_SetUsingAsCString(true); //debug
1710 
1711 	int32 len = Length();
1712 
1713 	if (maxLength > len) {
1714 		if (!_GrowBy(maxLength - len))
1715 			return NULL;
1716 		if (!len && _privateData)
1717 			// if string was empty before call to LockBuffer(), we make sure the
1718 			// buffer represents an empty c-string:
1719 			*_privateData = '\0';
1720 	} else if (!maxLength && !len) {
1721 		// special case for unallocated string, we return an empty c-string:
1722 		return const_cast<char*>(String());
1723 	}
1724 
1725 	return _privateData;
1726 }
1727 
1728 
1729 BString&
1730 BString::UnlockBuffer(int32 length)
1731 {
1732 	_SetUsingAsCString(false); //debug
1733 
1734 	int32 len = length;
1735 
1736 	if (len < 0)
1737 		len = (_privateData == NULL) ? 0 : strlen(_privateData);
1738 
1739 	if (len != Length())
1740 		_GrowBy(len - Length());
1741 
1742 	return *this;
1743 }
1744 
1745 
1746 /*---- Uppercase<->Lowercase ------------------------------------------------*/
1747 // ToLower
1748 /*! \brief Converts the BString to lowercase
1749 	\return This function always returns *this .
1750 */
1751 BString&
1752 BString::ToLower()
1753 {
1754 	int32 length = Length();
1755 	for (int32 count = 0; count < length; count++)
1756 			_privateData[count] = tolower(_privateData[count]);
1757 
1758 	return *this;
1759 }
1760 
1761 
1762 // ToUpper
1763 /*! \brief Converts the BString to uppercase
1764 	\return This function always returns *this .
1765 */
1766 BString&
1767 BString::ToUpper()
1768 {
1769 	int32 length = Length();
1770 	for (int32 count = 0; count < length; count++)
1771 			_privateData[count] = toupper(_privateData[count]);
1772 
1773 	return *this;
1774 }
1775 
1776 
1777 // Capitalize
1778 /*! \brief Converts the first character to uppercase, rest to lowercase
1779 	\return This function always returns *this .
1780 */
1781 BString&
1782 BString::Capitalize()
1783 {
1784 	if (_privateData == NULL)
1785 		return *this;
1786 
1787 	_privateData[0] = toupper(_privateData[0]);
1788 	int32 length = Length();
1789 
1790 	for (int32 count = 1; count < length; count++)
1791 			_privateData[count] = tolower(_privateData[count]);
1792 
1793 	return *this;
1794 }
1795 
1796 
1797 // CapitalizeEachWord
1798 /*! \brief Converts the first character of every word to uppercase, rest to lowercase.
1799 
1800 	Converts the first character of every "word" (series of alpabetical characters
1801 	separated by non alphabetical characters) to uppercase, and the rest to lowercase.
1802 	\return This function always returns *this .
1803 */
1804 BString&
1805 BString::CapitalizeEachWord()
1806 {
1807 	if (_privateData == NULL)
1808 		return *this;
1809 
1810 	int32 count = 0;
1811 	int32 length = Length();
1812 
1813 	do {
1814 		// Find the first alphabetical character...
1815 		for(; count < length; count++) {
1816 			if (isalpha(_privateData[count])) {
1817 				// ...found! Convert it to uppercase.
1818 				_privateData[count] = toupper(_privateData[count]);
1819 				count++;
1820 				break;
1821 			}
1822 		}
1823 		// Now find the first non-alphabetical character,
1824 		// and meanwhile, turn to lowercase all the alphabetical ones
1825 		for(; count < length; count++) {
1826 			if (isalpha(_privateData[count]))
1827 				_privateData[count] = tolower(_privateData[count]);
1828 			else
1829 				break;
1830 		}
1831 	} while (count < length);
1832 
1833 	return *this;
1834 }
1835 
1836 
1837 /*----- Escaping and Deescaping --------------------------------------------*/
1838 BString&
1839 BString::CharacterEscape(const char *original, const char *setOfCharsToEscape, char escapeWith)
1840 {
1841 	SetTo(original);
1842 	CharacterEscape(setOfCharsToEscape, escapeWith);
1843 
1844 	return *this;
1845 }
1846 
1847 
1848 BString&
1849 BString::CharacterEscape(const char *setOfCharsToEscape, char escapeWith)
1850 {
1851 	if (setOfCharsToEscape == NULL || _privateData == NULL)
1852 		return *this;
1853 
1854 	PosVect positions;
1855 	int32 len = Length();
1856 	int32 pos = 0;
1857 	for (int32 offset = 0; offset < len; offset += pos + 1) {
1858 		if ((pos = strcspn(_privateData + offset, setOfCharsToEscape)) < len - offset)
1859 			if (!positions.Add(offset + pos))
1860 				return *this;
1861 	}
1862 
1863 	uint32 count = positions.CountItems();
1864 	int32 newLength = len + count;
1865 	if (!newLength) {
1866 		_GrowBy( -len);
1867 		return *this;
1868 	}
1869 	int32 lastPos = 0;
1870 	char* oldAdr = _privateData;
1871 	char* newData = (char*)malloc(newLength + sizeof(int32) + 1);
1872 	if (newData) {
1873 		newData += sizeof(int32);
1874 		char* newAdr = newData;
1875 		for (uint32 i = 0; i < count; ++i) {
1876 			pos = positions.ItemAt( i);
1877 			len = pos-lastPos;
1878 			if (len > 0) {
1879 				memcpy(newAdr, oldAdr, len);
1880 				oldAdr += len;
1881 				newAdr += len;
1882 			}
1883 			*newAdr++ = escapeWith;
1884 			*newAdr++ = *oldAdr++;
1885 			lastPos = pos + 1;
1886 		}
1887 		len = Length() + 1 - lastPos;
1888 		if (len > 0)
1889 			memcpy(newAdr, oldAdr, len);
1890 
1891 		free(_privateData - sizeof(int32));
1892 		_privateData = newData;
1893 		_privateData[newLength] = 0;
1894 		_SetLength( newLength);
1895 	}
1896 
1897 	return *this;
1898 }
1899 
1900 
1901 BString&
1902 BString::CharacterDeescape(const char *original, char escapeChar)
1903 {
1904 	SetTo(original);
1905 	CharacterDeescape(escapeChar);
1906 
1907 	return *this;
1908 }
1909 
1910 
1911 BString&
1912 BString::CharacterDeescape(char escapeChar)
1913 {
1914 	const char temp[2] = {escapeChar, 0};
1915 	return _DoReplace(temp, "", REPLACE_ALL, 0, KEEP_CASE);
1916 }
1917 
1918 
1919 /*---- Simple sprintf replacement calls ------------------------------------*/
1920 /*---- Slower than sprintf but type and overflow safe ----------------------*/
1921 BString&
1922 BString::operator<<(const char *str)
1923 {
1924 	if (str != NULL)
1925 		_DoAppend(str, strlen(str));
1926 	return *this;
1927 }
1928 
1929 
1930 BString&
1931 BString::operator<<(const BString &string)
1932 {
1933 	_DoAppend(string.String(), string.Length());
1934 	return *this;
1935 }
1936 
1937 
1938 BString&
1939 BString::operator<<(char c)
1940 {
1941 	_DoAppend(&c, 1);
1942 	return *this;
1943 }
1944 
1945 
1946 BString&
1947 BString::operator<<(int i)
1948 {
1949 	char num[64];
1950 	sprintf(num, "%d", i);
1951 
1952 	return *this << num;
1953 }
1954 
1955 
1956 BString&
1957 BString::operator<<(unsigned int i)
1958 {
1959 	char num[64];
1960 	sprintf(num, "%u", i);
1961 
1962 	return *this << num;
1963 }
1964 
1965 
1966 BString&
1967 BString::operator<<(uint32 i)
1968 {
1969 	char num[64];
1970 	sprintf(num, "%lu", i);
1971 
1972 	return *this << num;
1973 }
1974 
1975 
1976 BString&
1977 BString::operator<<(int32 i)
1978 {
1979 	char num[64];
1980 	sprintf(num, "%ld", i);
1981 
1982 	return *this << num;
1983 }
1984 
1985 
1986 BString&
1987 BString::operator<<(uint64 i)
1988 {
1989 	char num[64];
1990 	sprintf(num, "%llu", i);
1991 
1992 	return *this << num;
1993 }
1994 
1995 
1996 BString&
1997 BString::operator<<(int64 i)
1998 {
1999 	char num[64];
2000 	sprintf(num, "%lld", i);
2001 
2002 	return *this << num;
2003 }
2004 
2005 
2006 BString&
2007 BString::operator<<(float f)
2008 {
2009 	char num[64];
2010 	sprintf(num, "%.2f", f);
2011 
2012 	return *this << num;
2013 }
2014 
2015 
2016 /*---- Private or Reserved ------------------------------------------------*/
2017 char*
2018 BString::_Alloc(int32 dataLen)
2019 {
2020 	char *dataPtr = _privateData ? _privateData - sizeof(int32) : NULL;
2021 	if (dataLen <= 0) {	// release buffer if requested size is 0:
2022 		free(dataPtr);
2023 		_privateData = NULL;
2024 		return NULL;
2025 	}
2026 	int32 allocLen = dataLen + sizeof(int32) + 1;
2027 	dataPtr = (char *)realloc(dataPtr, allocLen);
2028 	if (dataPtr) {
2029 		dataPtr += sizeof(int32);
2030 		_privateData = dataPtr;
2031 		int32 newLen = allocLen - sizeof(int32) - 1;
2032 		_SetLength(newLen);
2033 		_privateData[newLen] = '\0';
2034 	}
2035 	return dataPtr;
2036 }
2037 
2038 void
2039 BString::_Init(const char *str, int32 len)
2040 {
2041 	if (_Alloc(len))
2042 		memcpy(_privateData, str, len);
2043 }
2044 
2045 
2046 #if ENABLE_INLINES
2047 inline
2048 #endif
2049 void
2050 BString::_DoAssign(const char *str, int32 len)
2051 {
2052 	int32 curLen = Length();
2053 
2054 	if (len == curLen || _GrowBy(len - curLen))
2055 		memcpy(_privateData, str, len);
2056 }
2057 
2058 
2059 #if ENABLE_INLINES
2060 inline
2061 #endif
2062 void
2063 BString::_DoAppend(const char *str, int32 len)
2064 {
2065 	int32 length = Length();
2066 	if (_GrowBy(len))
2067 		memcpy(_privateData + length, str, len);
2068 }
2069 
2070 
2071 char*
2072 BString::_GrowBy(int32 size)
2073 {
2074 	int32 newLen = Length() + size;
2075 	return _Alloc(newLen);
2076 }
2077 
2078 
2079 char *
2080 BString::_OpenAtBy(int32 offset, int32 length)
2081 {
2082 	int32 oldLength = Length();
2083 
2084 	char* newData = _Alloc(oldLength + length);
2085 	if (newData != NULL)
2086 		memmove(_privateData + offset + length, _privateData + offset,
2087 				  oldLength - offset);
2088 
2089 	return newData;
2090 }
2091 
2092 
2093 char*
2094 BString::_ShrinkAtBy(int32 offset, int32 length)
2095 {
2096 	if (!_privateData)
2097 		return NULL;
2098 	int32 oldLength = Length();
2099 
2100 	memmove(_privateData + offset, _privateData + offset + length,
2101 		     oldLength - offset - length);
2102 
2103 	// the following actually should never fail, since we are reducing the size...
2104 	return _Alloc(oldLength - length);
2105 }
2106 
2107 
2108 #if ENABLE_INLINES
2109 inline
2110 #endif
2111 void
2112 BString::_DoPrepend(const char *str, int32 count)
2113 {
2114 	if (_OpenAtBy(0, count))
2115 		memcpy(_privateData, str, count);
2116 }
2117 
2118 
2119 /* XXX: These could be inlined too, if they are too slow */
2120 int32
2121 BString::_FindAfter(const char *str, int32 offset, int32 strlen) const
2122 {
2123 	char *ptr = strstr(String() + offset, str);
2124 
2125 	if (ptr != NULL)
2126 		return ptr - String();
2127 
2128 	return B_ERROR;
2129 }
2130 
2131 
2132 int32
2133 BString::_IFindAfter(const char *str, int32 offset, int32 strlen) const
2134 {
2135 	char *ptr = strcasestr(String() + offset, str);
2136 
2137 	if (ptr != NULL)
2138 		return ptr - String();
2139 
2140 	return B_ERROR;
2141 }
2142 
2143 
2144 int32
2145 BString::_ShortFindAfter(const char *str, int32 len) const
2146 {
2147 	char *ptr = strstr(String(), str);
2148 
2149 	if (ptr != NULL)
2150 		return ptr - String();
2151 
2152 	return B_ERROR;
2153 }
2154 
2155 
2156 int32
2157 BString::_FindBefore(const char *str, int32 offset, int32 strlen) const
2158 {
2159 	if (_privateData) {
2160 		const char *ptr = _privateData + offset - strlen;
2161 
2162 		while (ptr >= _privateData) {
2163 			if (!memcmp(ptr, str, strlen))
2164 				return ptr - _privateData;
2165 			ptr--;
2166 		}
2167 	}
2168 	return B_ERROR;
2169 }
2170 
2171 
2172 int32
2173 BString::_IFindBefore(const char *str, int32 offset, int32 strlen) const
2174 {
2175 	if (_privateData) {
2176 		char *ptr1 = _privateData + offset - strlen;
2177 
2178 		while (ptr1 >= _privateData) {
2179 			if (!strncasecmp(ptr1, str, strlen))
2180 				return ptr1 - _privateData;
2181 			ptr1--;
2182 		}
2183 	}
2184 	return B_ERROR;
2185 }
2186 
2187 
2188 BString&
2189 BString::_DoReplace(const char *findThis, const char *replaceWith, int32 maxReplaceCount,
2190 						  int32 fromOffset,	bool ignoreCase)
2191 {
2192 	if (findThis == NULL || maxReplaceCount <= 0
2193 		|| fromOffset < 0 || fromOffset >= Length())
2194 		return *this;
2195 
2196 	typedef int32 (BString::*TFindMethod)(const char *, int32, int32) const;
2197 	TFindMethod findMethod = ignoreCase ? &BString::_IFindAfter : &BString::_FindAfter;
2198 	int32 findLen = strlen(findThis);
2199 
2200 	if (!replaceWith)
2201 		replaceWith = "";
2202 
2203 	int32 replaceLen = strlen(replaceWith);
2204 	int32 lastSrcPos = fromOffset;
2205 	PosVect positions;
2206 	for(int32 srcPos = 0;
2207 			maxReplaceCount > 0
2208 			&& (srcPos = (this->*findMethod)(findThis, lastSrcPos, findLen)) >= 0;
2209 			maxReplaceCount-- ) {
2210 		positions.Add(srcPos);
2211 		lastSrcPos = srcPos + findLen;
2212 	}
2213 	_ReplaceAtPositions(&positions, findLen, replaceWith, replaceLen);
2214 	return *this;
2215 }
2216 
2217 
2218 void
2219 BString::_ReplaceAtPositions(const PosVect* positions,
2220 											  int32 searchLen, const char* with,
2221 											  int32 withLen)
2222 {
2223 	int32 len = Length();
2224 	uint32 count = positions->CountItems();
2225 	int32 newLength = len + count * (withLen - searchLen);
2226 	if (!newLength) {
2227 		_GrowBy(-len);
2228 		return;
2229 	}
2230 	int32 pos;
2231 	int32 lastPos = 0;
2232 	char *oldAdr = _privateData;
2233 	char *newData = (char *)malloc(newLength + sizeof(int32) + 1);
2234 	if (newData) {
2235 		newData += sizeof(int32);
2236 		char *newAdr = newData;
2237 		for(uint32 i = 0; i < count; ++i) {
2238 			pos = positions->ItemAt(i);
2239 			len = pos - lastPos;
2240 			if (len > 0) {
2241 				memcpy(newAdr, oldAdr, len);
2242 				oldAdr += len;
2243 				newAdr += len;
2244 			}
2245 			memcpy(newAdr, with, withLen);
2246 			oldAdr += searchLen;
2247 			newAdr += withLen;
2248 			lastPos = pos+searchLen;
2249 		}
2250 		len = Length() + 1 - lastPos;
2251 		if (len > 0)
2252 			memcpy(newAdr, oldAdr, len);
2253 
2254 		free(_privateData - sizeof(int32));
2255 		_privateData = newData;
2256 		_privateData[newLength] = 0;
2257 		_SetLength( newLength);
2258 	}
2259 }
2260 
2261 
2262 #if ENABLE_INLINES
2263 inline
2264 #endif
2265 void
2266 BString::_SetLength(int32 length)
2267 {
2268 	*((int32*)_privateData - 1) = length & 0x7fffffff;
2269 }
2270 
2271 
2272 #if DEBUG
2273 // AFAIK, these are not implemented in BeOS R5
2274 // XXX : Test these puppies
2275 void
2276 BString::_SetUsingAsCString(bool state)
2277 {
2278 	//TODO: Implement ?
2279 }
2280 
2281 
2282 void
2283 BString::_AssertNotUsingAsCString() const
2284 {
2285 	//TODO: Implement ?
2286 }
2287 #endif
2288 
2289 
2290 /*----- Non-member compare for sorting, etc. ------------------------------*/
2291 int
2292 Compare(const BString &string1, const BString &string2)
2293 {
2294 	return strcmp(string1.String(), string2.String());
2295 }
2296 
2297 
2298 int
2299 ICompare(const BString &string1, const BString &string2)
2300 {
2301 	return strcasecmp(string1.String(), string2.String());
2302 }
2303 
2304 
2305 int
2306 Compare(const BString *string1, const BString *string2)
2307 {
2308 	return strcmp(string1->String(), string2->String());
2309 }
2310 
2311 
2312 int
2313 ICompare(const BString *string1, const BString *string2)
2314 {
2315 	return strcasecmp(string1->String(), string2->String());
2316 }
2317 
2318