xref: /haiku/src/kits/support/String.cpp (revision 5d9e40fe9252c8f9c5e5e41594545bfa4419fcc7)
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 	if (length < 0)
1735 		length = (_privateData == NULL) ? 0 : strlen(_privateData);
1736 
1737 	if (length != Length())
1738 		_GrowBy(length - Length());
1739 
1740 	return *this;
1741 }
1742 
1743 
1744 /*---- Uppercase<->Lowercase ------------------------------------------------*/
1745 // ToLower
1746 /*! \brief Converts the BString to lowercase
1747 	\return This function always returns *this .
1748 */
1749 BString&
1750 BString::ToLower()
1751 {
1752 	int32 length = Length();
1753 	for (int32 count = 0; count < length; count++)
1754 			_privateData[count] = tolower(_privateData[count]);
1755 
1756 	return *this;
1757 }
1758 
1759 
1760 // ToUpper
1761 /*! \brief Converts the BString to uppercase
1762 	\return This function always returns *this .
1763 */
1764 BString&
1765 BString::ToUpper()
1766 {
1767 	int32 length = Length();
1768 	for (int32 count = 0; count < length; count++)
1769 			_privateData[count] = toupper(_privateData[count]);
1770 
1771 	return *this;
1772 }
1773 
1774 
1775 // Capitalize
1776 /*! \brief Converts the first character to uppercase, rest to lowercase
1777 	\return This function always returns *this .
1778 */
1779 BString&
1780 BString::Capitalize()
1781 {
1782 	if (_privateData == NULL)
1783 		return *this;
1784 
1785 	_privateData[0] = toupper(_privateData[0]);
1786 	int32 length = Length();
1787 
1788 	for (int32 count = 1; count < length; count++)
1789 			_privateData[count] = tolower(_privateData[count]);
1790 
1791 	return *this;
1792 }
1793 
1794 
1795 // CapitalizeEachWord
1796 /*! \brief Converts the first character of every word to uppercase, rest to lowercase.
1797 
1798 	Converts the first character of every "word" (series of alpabetical characters
1799 	separated by non alphabetical characters) to uppercase, and the rest to lowercase.
1800 	\return This function always returns *this .
1801 */
1802 BString&
1803 BString::CapitalizeEachWord()
1804 {
1805 	if (_privateData == NULL)
1806 		return *this;
1807 
1808 	int32 count = 0;
1809 	int32 length = Length();
1810 
1811 	do {
1812 		// Find the first alphabetical character...
1813 		for(; count < length; count++) {
1814 			if (isalpha(_privateData[count])) {
1815 				// ...found! Convert it to uppercase.
1816 				_privateData[count] = toupper(_privateData[count]);
1817 				count++;
1818 				break;
1819 			}
1820 		}
1821 		// Now find the first non-alphabetical character,
1822 		// and meanwhile, turn to lowercase all the alphabetical ones
1823 		for(; count < length; count++) {
1824 			if (isalpha(_privateData[count]))
1825 				_privateData[count] = tolower(_privateData[count]);
1826 			else
1827 				break;
1828 		}
1829 	} while (count < length);
1830 
1831 	return *this;
1832 }
1833 
1834 
1835 /*----- Escaping and Deescaping --------------------------------------------*/
1836 BString&
1837 BString::CharacterEscape(const char *original, const char *setOfCharsToEscape, char escapeWith)
1838 {
1839 	SetTo(original);
1840 	CharacterEscape(setOfCharsToEscape, escapeWith);
1841 
1842 	return *this;
1843 }
1844 
1845 
1846 BString&
1847 BString::CharacterEscape(const char *setOfCharsToEscape, char escapeWith)
1848 {
1849 	if (setOfCharsToEscape == NULL || _privateData == NULL)
1850 		return *this;
1851 
1852 	PosVect positions;
1853 	int32 len = Length();
1854 	int32 pos = 0;
1855 	for (int32 offset = 0; offset < len; offset += pos + 1) {
1856 		if ((pos = strcspn(_privateData + offset, setOfCharsToEscape)) < len - offset)
1857 			if (!positions.Add(offset + pos))
1858 				return *this;
1859 	}
1860 
1861 	uint32 count = positions.CountItems();
1862 	int32 newLength = len + count;
1863 	if (!newLength) {
1864 		_GrowBy( -len);
1865 		return *this;
1866 	}
1867 	int32 lastPos = 0;
1868 	char* oldAdr = _privateData;
1869 	char* newData = (char*)malloc(newLength + sizeof(int32) + 1);
1870 	if (newData) {
1871 		newData += sizeof(int32);
1872 		char* newAdr = newData;
1873 		for (uint32 i = 0; i < count; ++i) {
1874 			pos = positions.ItemAt( i);
1875 			len = pos-lastPos;
1876 			if (len > 0) {
1877 				memcpy(newAdr, oldAdr, len);
1878 				oldAdr += len;
1879 				newAdr += len;
1880 			}
1881 			*newAdr++ = escapeWith;
1882 			*newAdr++ = *oldAdr++;
1883 			lastPos = pos + 1;
1884 		}
1885 		len = Length() + 1 - lastPos;
1886 		if (len > 0)
1887 			memcpy(newAdr, oldAdr, len);
1888 
1889 		free(_privateData - sizeof(int32));
1890 		_privateData = newData;
1891 		_privateData[newLength] = 0;
1892 		_SetLength( newLength);
1893 	}
1894 
1895 	return *this;
1896 }
1897 
1898 
1899 BString&
1900 BString::CharacterDeescape(const char *original, char escapeChar)
1901 {
1902 	SetTo(original);
1903 	CharacterDeescape(escapeChar);
1904 
1905 	return *this;
1906 }
1907 
1908 
1909 BString&
1910 BString::CharacterDeescape(char escapeChar)
1911 {
1912 	const char temp[2] = {escapeChar, 0};
1913 	return _DoReplace(temp, "", REPLACE_ALL, 0, KEEP_CASE);
1914 }
1915 
1916 
1917 /*---- Simple sprintf replacement calls ------------------------------------*/
1918 /*---- Slower than sprintf but type and overflow safe ----------------------*/
1919 BString&
1920 BString::operator<<(const char *str)
1921 {
1922 	if (str != NULL)
1923 		_DoAppend(str, strlen(str));
1924 	return *this;
1925 }
1926 
1927 
1928 BString&
1929 BString::operator<<(const BString &string)
1930 {
1931 	_DoAppend(string.String(), string.Length());
1932 	return *this;
1933 }
1934 
1935 
1936 BString&
1937 BString::operator<<(char c)
1938 {
1939 	_DoAppend(&c, 1);
1940 	return *this;
1941 }
1942 
1943 
1944 BString&
1945 BString::operator<<(int i)
1946 {
1947 	char num[64];
1948 	sprintf(num, "%d", i);
1949 
1950 	return *this << num;
1951 }
1952 
1953 
1954 BString&
1955 BString::operator<<(unsigned int i)
1956 {
1957 	char num[64];
1958 	sprintf(num, "%u", i);
1959 
1960 	return *this << num;
1961 }
1962 
1963 
1964 BString&
1965 BString::operator<<(uint32 i)
1966 {
1967 	char num[64];
1968 	sprintf(num, "%lu", i);
1969 
1970 	return *this << num;
1971 }
1972 
1973 
1974 BString&
1975 BString::operator<<(int32 i)
1976 {
1977 	char num[64];
1978 	sprintf(num, "%ld", i);
1979 
1980 	return *this << num;
1981 }
1982 
1983 
1984 BString&
1985 BString::operator<<(uint64 i)
1986 {
1987 	char num[64];
1988 	sprintf(num, "%llu", i);
1989 
1990 	return *this << num;
1991 }
1992 
1993 
1994 BString&
1995 BString::operator<<(int64 i)
1996 {
1997 	char num[64];
1998 	sprintf(num, "%lld", i);
1999 
2000 	return *this << num;
2001 }
2002 
2003 
2004 BString&
2005 BString::operator<<(float f)
2006 {
2007 	char num[64];
2008 	sprintf(num, "%.2f", f);
2009 
2010 	return *this << num;
2011 }
2012 
2013 
2014 /*---- Private or Reserved ------------------------------------------------*/
2015 char *
2016 BString::_Alloc(int32 dataLen)
2017 {
2018 	char *dataPtr = _privateData ? _privateData - sizeof(int32) : NULL;
2019 	if (dataLen <= 0) {	// release buffer if requested size is 0:
2020 		free(dataPtr);
2021 		_privateData = NULL;
2022 		return NULL;
2023 	}
2024 	int32 allocLen = dataLen + sizeof(int32) + 1;
2025 	dataPtr = (char *)realloc(dataPtr, allocLen);
2026 	if (dataPtr) {
2027 		dataPtr += sizeof(int32);
2028 		_privateData = dataPtr;
2029 
2030 		_SetLength(dataLen);
2031 		_privateData[dataLen] = '\0';
2032 	}
2033 	return dataPtr;
2034 }
2035 
2036 void
2037 BString::_Init(const char *str, int32 len)
2038 {
2039 	if (_Alloc(len))
2040 		memcpy(_privateData, str, len);
2041 }
2042 
2043 
2044 #if ENABLE_INLINES
2045 inline
2046 #endif
2047 void
2048 BString::_DoAssign(const char *str, int32 len)
2049 {
2050 	int32 curLen = Length();
2051 
2052 	if (len == curLen || _GrowBy(len - curLen))
2053 		memcpy(_privateData, str, len);
2054 }
2055 
2056 
2057 #if ENABLE_INLINES
2058 inline
2059 #endif
2060 void
2061 BString::_DoAppend(const char *str, int32 len)
2062 {
2063 	int32 length = Length();
2064 	if (_GrowBy(len))
2065 		memcpy(_privateData + length, str, len);
2066 }
2067 
2068 
2069 char*
2070 BString::_GrowBy(int32 size)
2071 {
2072 	int32 newLen = Length() + size;
2073 	return _Alloc(newLen);
2074 }
2075 
2076 
2077 char *
2078 BString::_OpenAtBy(int32 offset, int32 length)
2079 {
2080 	int32 oldLength = Length();
2081 
2082 	char* newData = _Alloc(oldLength + length);
2083 	if (newData != NULL)
2084 		memmove(_privateData + offset + length, _privateData + offset,
2085 				  oldLength - offset);
2086 
2087 	return newData;
2088 }
2089 
2090 
2091 char*
2092 BString::_ShrinkAtBy(int32 offset, int32 length)
2093 {
2094 	if (!_privateData)
2095 		return NULL;
2096 	int32 oldLength = Length();
2097 
2098 	memmove(_privateData + offset, _privateData + offset + length,
2099 		     oldLength - offset - length);
2100 
2101 	// the following actually should never fail, since we are reducing the size...
2102 	return _Alloc(oldLength - length);
2103 }
2104 
2105 
2106 #if ENABLE_INLINES
2107 inline
2108 #endif
2109 void
2110 BString::_DoPrepend(const char *str, int32 count)
2111 {
2112 	if (_OpenAtBy(0, count))
2113 		memcpy(_privateData, str, count);
2114 }
2115 
2116 
2117 /* XXX: These could be inlined too, if they are too slow */
2118 int32
2119 BString::_FindAfter(const char *str, int32 offset, int32 strlen) const
2120 {
2121 	char *ptr = strstr(String() + offset, str);
2122 
2123 	if (ptr != NULL)
2124 		return ptr - String();
2125 
2126 	return B_ERROR;
2127 }
2128 
2129 
2130 int32
2131 BString::_IFindAfter(const char *str, int32 offset, int32 strlen) const
2132 {
2133 	char *ptr = strcasestr(String() + offset, str);
2134 
2135 	if (ptr != NULL)
2136 		return ptr - String();
2137 
2138 	return B_ERROR;
2139 }
2140 
2141 
2142 int32
2143 BString::_ShortFindAfter(const char *str, int32 len) const
2144 {
2145 	char *ptr = strstr(String(), str);
2146 
2147 	if (ptr != NULL)
2148 		return ptr - String();
2149 
2150 	return B_ERROR;
2151 }
2152 
2153 
2154 int32
2155 BString::_FindBefore(const char *str, int32 offset, int32 strlen) const
2156 {
2157 	if (_privateData) {
2158 		const char *ptr = _privateData + offset - strlen;
2159 
2160 		while (ptr >= _privateData) {
2161 			if (!memcmp(ptr, str, strlen))
2162 				return ptr - _privateData;
2163 			ptr--;
2164 		}
2165 	}
2166 	return B_ERROR;
2167 }
2168 
2169 
2170 int32
2171 BString::_IFindBefore(const char *str, int32 offset, int32 strlen) const
2172 {
2173 	if (_privateData) {
2174 		char *ptr1 = _privateData + offset - strlen;
2175 
2176 		while (ptr1 >= _privateData) {
2177 			if (!strncasecmp(ptr1, str, strlen))
2178 				return ptr1 - _privateData;
2179 			ptr1--;
2180 		}
2181 	}
2182 	return B_ERROR;
2183 }
2184 
2185 
2186 BString&
2187 BString::_DoReplace(const char *findThis, const char *replaceWith, int32 maxReplaceCount,
2188 						  int32 fromOffset,	bool ignoreCase)
2189 {
2190 	if (findThis == NULL || maxReplaceCount <= 0
2191 		|| fromOffset < 0 || fromOffset >= Length())
2192 		return *this;
2193 
2194 	typedef int32 (BString::*TFindMethod)(const char *, int32, int32) const;
2195 	TFindMethod findMethod = ignoreCase ? &BString::_IFindAfter : &BString::_FindAfter;
2196 	int32 findLen = strlen(findThis);
2197 
2198 	if (!replaceWith)
2199 		replaceWith = "";
2200 
2201 	int32 replaceLen = strlen(replaceWith);
2202 	int32 lastSrcPos = fromOffset;
2203 	PosVect positions;
2204 	for(int32 srcPos = 0;
2205 			maxReplaceCount > 0
2206 			&& (srcPos = (this->*findMethod)(findThis, lastSrcPos, findLen)) >= 0;
2207 			maxReplaceCount-- ) {
2208 		positions.Add(srcPos);
2209 		lastSrcPos = srcPos + findLen;
2210 	}
2211 	_ReplaceAtPositions(&positions, findLen, replaceWith, replaceLen);
2212 	return *this;
2213 }
2214 
2215 
2216 void
2217 BString::_ReplaceAtPositions(const PosVect* positions,
2218 											  int32 searchLen, const char* with,
2219 											  int32 withLen)
2220 {
2221 	int32 len = Length();
2222 	uint32 count = positions->CountItems();
2223 	int32 newLength = len + count * (withLen - searchLen);
2224 	if (!newLength) {
2225 		_GrowBy(-len);
2226 		return;
2227 	}
2228 	int32 pos;
2229 	int32 lastPos = 0;
2230 	char *oldAdr = _privateData;
2231 	char *newData = (char *)malloc(newLength + sizeof(int32) + 1);
2232 	if (newData) {
2233 		newData += sizeof(int32);
2234 		char *newAdr = newData;
2235 		for(uint32 i = 0; i < count; ++i) {
2236 			pos = positions->ItemAt(i);
2237 			len = pos - lastPos;
2238 			if (len > 0) {
2239 				memcpy(newAdr, oldAdr, len);
2240 				oldAdr += len;
2241 				newAdr += len;
2242 			}
2243 			memcpy(newAdr, with, withLen);
2244 			oldAdr += searchLen;
2245 			newAdr += withLen;
2246 			lastPos = pos+searchLen;
2247 		}
2248 		len = Length() + 1 - lastPos;
2249 		if (len > 0)
2250 			memcpy(newAdr, oldAdr, len);
2251 
2252 		free(_privateData - sizeof(int32));
2253 		_privateData = newData;
2254 		_privateData[newLength] = 0;
2255 		_SetLength( newLength);
2256 	}
2257 }
2258 
2259 
2260 #if ENABLE_INLINES
2261 inline
2262 #endif
2263 void
2264 BString::_SetLength(int32 length)
2265 {
2266 	*((int32*)_privateData - 1) = length & 0x7fffffff;
2267 }
2268 
2269 
2270 #if DEBUG
2271 // AFAIK, these are not implemented in BeOS R5
2272 // XXX : Test these puppies
2273 void
2274 BString::_SetUsingAsCString(bool state)
2275 {
2276 	//TODO: Implement ?
2277 }
2278 
2279 
2280 void
2281 BString::_AssertNotUsingAsCString() const
2282 {
2283 	//TODO: Implement ?
2284 }
2285 #endif
2286 
2287 
2288 /*----- Non-member compare for sorting, etc. ------------------------------*/
2289 int
2290 Compare(const BString &string1, const BString &string2)
2291 {
2292 	return strcmp(string1.String(), string2.String());
2293 }
2294 
2295 
2296 int
2297 ICompare(const BString &string1, const BString &string2)
2298 {
2299 	return strcasecmp(string1.String(), string2.String());
2300 }
2301 
2302 
2303 int
2304 Compare(const BString *string1, const BString *string2)
2305 {
2306 	return strcmp(string1->String(), string2->String());
2307 }
2308 
2309 
2310 int
2311 ICompare(const BString *string1, const BString *string2)
2312 {
2313 	return strcasecmp(string1->String(), string2->String());
2314 }
2315 
2316