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