15b506de7SNiels Sascha Reedijk/*
229e8fa59SJohn Scipione * Copyright 2001-2014 Haiku, Inc. All rights reserved.
3e52400cfSAxel Dörfler * Distributed under the terms of the MIT License.
4e52400cfSAxel Dörfler *
5e52400cfSAxel Dörfler * Authors:
629e8fa59SJohn Scipione *		Stefano Ceccherini, burton666@libero.it
7e52400cfSAxel Dörfler *		Axel D��rfler, axeld@pinc-software.de
829e8fa59SJohn Scipione *		Marc Flerackers, mflerackers@androme.be
929e8fa59SJohn Scipione *		Julun, host.haiku@gmx.de
1029e8fa59SJohn Scipione *		Michael Lotz, mmlr@mlotz.ch
1129e8fa59SJohn Scipione *		Oliver Tappe, openbeos@hirschkaefer.de
12e52400cfSAxel Dörfler */
13e6a6424eSAxel Dörfler
14e90b90daSAxel Dörfler
15002b33b7SAxel Dörfler/*! String class supporting common string operations. */
16e6a6424eSAxel Dörfler
179d214f41SClemens Zeidler#include <String.h>
189d214f41SClemens Zeidler
19e6a6424eSAxel Dörfler#include <ctype.h>
208e3f5e89SFrançois Revol#include <stdint.h>
21e6a6424eSAxel Dörfler#include <stdio.h>
22e6a6424eSAxel Dörfler#include <stdlib.h>
233aeed660SJérôme Duval#include <strings.h>
24e6a6424eSAxel Dörfler
25e52400cfSAxel Dörfler#include <Debug.h>
26c82776b2SIngo Weinhold#include <StringList.h>
27e6a6424eSAxel Dörfler
28d0c41784SIngo Weinhold#include <StringPrivate.h>
29a5b7cbe3SMichael Lotz#include <utf8_functions.h>
30a5b7cbe3SMichael Lotz
31a8dee23eSStefano Ceccherini
321783edd5SStefano Ceccherini// define proper names for case-option of _DoReplace()
331783edd5SStefano Ceccherini#define KEEP_CASE false
341783edd5SStefano Ceccherini#define IGNORE_CASE true
351783edd5SStefano Ceccherini
365480b459SStefano Ceccherini// define proper names for count-option of _DoReplace()
375480b459SStefano Ceccherini#define REPLACE_ALL 0x7FFFFFFF
385480b459SStefano Ceccherini
395480b459SStefano Ceccherini
40d0c41784SIngo Weinholdstatic const uint32 kPrivateDataOffset = BString::Private::kPrivateDataOffset;
41002b33b7SAxel Dörfler
42e52400cfSAxel Dörflerconst char* B_EMPTY_STRING = "";
43ba8e3cf1SAxel Dörfler
44ba8e3cf1SAxel Dörfler
451ea1a6b4SNiels Sascha Reedijk// helper function, returns minimum of two given values (but clamps to 0):
465480b459SStefano Ceccherinistatic inline int32
47576e2bf8SStefano Ceccherinimin_clamp0(int32 num1, int32 num2)
48576e2bf8SStefano Ceccherini{
49e6a6424eSAxel Dörfler	if (num1 < num2)
505480b459SStefano Ceccherini		return num1 > 0 ? num1 : 0;
51e6a6424eSAxel Dörfler
52e6a6424eSAxel Dörfler	return num2 > 0 ? num2 : 0;
535480b459SStefano Ceccherini}
545480b459SStefano Ceccherini
555480b459SStefano Ceccherini
56e52400cfSAxel Dörfler//! Returns length of given string (but clamps to given maximum).
575480b459SStefano Ceccherinistatic inline int32
5829e8fa59SJohn Scipionestrlen_clamp(const char* string, int32 max)
5943cca04aSAxel Dörfler{
6043cca04aSAxel Dörfler	// this should yield 0 for max<0:
6129e8fa59SJohn Scipione	return max <= 0 ? 0 : strnlen(string, max);
625480b459SStefano Ceccherini}
635480b459SStefano Ceccherini
645480b459SStefano Ceccherini
65e52400cfSAxel Dörfler//! Helper function for strlen() that can handle NULL strings.
66e52400cfSAxel Dörflerstatic inline size_t
67e52400cfSAxel Dörflerstring_length(const char* string)
68e52400cfSAxel Dörfler{
69e52400cfSAxel Dörfler	return string != NULL ? strlen(string) : 0;
70e52400cfSAxel Dörfler}
71e52400cfSAxel Dörfler
72e52400cfSAxel Dörfler
7343cca04aSAxel Dörfler//! helper function, massages given pointer into a legal c-string:
74e52400cfSAxel Dörflerstatic inline const char*
7529e8fa59SJohn Scipionesafestr(const char* string)
765480b459SStefano Ceccherini{
7729e8fa59SJohn Scipione	return string != NULL ? string : "";
785480b459SStefano Ceccherini}
795480b459SStefano Ceccherini
805480b459SStefano Ceccherini
81576e2bf8SStefano Ceccherini//	#pragma mark - PosVect
82576e2bf8SStefano Ceccherini
83576e2bf8SStefano Ceccherini
84576e2bf8SStefano Ceccheriniclass BString::PosVect {
85576e2bf8SStefano Ceccherinipublic:
86576e2bf8SStefano Ceccherini	PosVect()
87e52400cfSAxel Dörfler		:
88e52400cfSAxel Dörfler		fSize(0),
89576e2bf8SStefano Ceccherini		fBufferSize(20),
90e52400cfSAxel Dörfler		fBuffer(NULL)
91e52400cfSAxel Dörfler	{
92e52400cfSAxel Dörfler	}
93576e2bf8SStefano Ceccherini
94576e2bf8SStefano Ceccherini	~PosVect()
95576e2bf8SStefano Ceccherini	{
96576e2bf8SStefano Ceccherini		free(fBuffer);
97576e2bf8SStefano Ceccherini	}
98576e2bf8SStefano Ceccherini
99576e2bf8SStefano Ceccherini	bool Add(int32 pos)
100576e2bf8SStefano Ceccherini	{
101576e2bf8SStefano Ceccherini		if (fBuffer == NULL || fSize == fBufferSize) {
102576e2bf8SStefano Ceccherini			if (fBuffer != NULL)
103576e2bf8SStefano Ceccherini				fBufferSize *= 2;
104576e2bf8SStefano Ceccherini
105137ac199SMurai Takashi			int32* newBuffer =
106137ac199SMurai Takashi				(int32*)realloc(fBuffer, fBufferSize * sizeof(int32));
107576e2bf8SStefano Ceccherini			if (newBuffer == NULL)
108576e2bf8SStefano Ceccherini				return false;
109576e2bf8SStefano Ceccherini
110576e2bf8SStefano Ceccherini			fBuffer = newBuffer;
111576e2bf8SStefano Ceccherini		}
112576e2bf8SStefano Ceccherini
113576e2bf8SStefano Ceccherini		fBuffer[fSize++] = pos;
11429e8fa59SJohn Scipione
115576e2bf8SStefano Ceccherini		return true;
116576e2bf8SStefano Ceccherini	}
117576e2bf8SStefano Ceccherini
118576e2bf8SStefano Ceccherini	inline int32 ItemAt(int32 index) const
119e52400cfSAxel Dörfler	{
120e52400cfSAxel Dörfler		return fBuffer[index];
121e52400cfSAxel Dörfler	}
122e52400cfSAxel Dörfler
123576e2bf8SStefano Ceccherini	inline int32 CountItems() const
124e52400cfSAxel Dörfler	{
125e52400cfSAxel Dörfler		return fSize;
126e52400cfSAxel Dörfler	}
127576e2bf8SStefano Ceccherini
128576e2bf8SStefano Ceccheriniprivate:
129576e2bf8SStefano Ceccherini	int32	fSize;
130576e2bf8SStefano Ceccherini	int32	fBufferSize;
131576e2bf8SStefano Ceccherini	int32*	fBuffer;
132576e2bf8SStefano Ceccherini};
133576e2bf8SStefano Ceccherini
134e6a6424eSAxel Dörfler
13543cca04aSAxel Dörfler//	#pragma mark - BString
1365480b459SStefano Ceccherini
137a8dee23eSStefano Ceccherini
138077c84ebSPawel Dziepakinline int32&
1391746066cSIngo WeinholdBString::_ReferenceCount()
1401746066cSIngo Weinhold{
141d0c41784SIngo Weinhold	return Private::DataRefCount(fPrivateData);
1421746066cSIngo Weinhold}
1431746066cSIngo Weinhold
1441746066cSIngo Weinhold
145077c84ebSPawel Dziepakinline const int32&
1461746066cSIngo WeinholdBString::_ReferenceCount() const
1471746066cSIngo Weinhold{
148d0c41784SIngo Weinhold	return Private::DataRefCount(fPrivateData);
1491746066cSIngo Weinhold}
1501746066cSIngo Weinhold
1511746066cSIngo Weinhold
1521746066cSIngo Weinholdinline bool
1531746066cSIngo WeinholdBString::_IsShareable() const
1541746066cSIngo Weinhold{
1551746066cSIngo Weinhold	return fPrivateData != NULL && _ReferenceCount() >= 0;
1561746066cSIngo Weinhold}
1571746066cSIngo Weinhold
1581746066cSIngo Weinhold
1597c830dc4SStefano CeccheriniBString::BString()
160e52400cfSAxel Dörfler	:
161e52400cfSAxel Dörfler	fPrivateData(NULL)
1629a82280aSStefano Ceccherini{
163576e2bf8SStefano Ceccherini	_Init("", 0);
1649a82280aSStefano Ceccherini}
1659a82280aSStefano Ceccherini
1669a82280aSStefano Ceccherini
16743cca04aSAxel DörflerBString::BString(const char* string)
168e52400cfSAxel Dörfler	:
169e52400cfSAxel Dörfler	fPrivateData(NULL)
1709a82280aSStefano Ceccherini{
171576e2bf8SStefano Ceccherini	_Init(string, strlen(safestr(string)));
1729a82280aSStefano Ceccherini}
1739a82280aSStefano Ceccherini
1749a82280aSStefano Ceccherini
175576e2bf8SStefano CeccheriniBString::BString(const BString& string)
176e52400cfSAxel Dörfler	:
177e52400cfSAxel Dörfler	fPrivateData(NULL)
1789a82280aSStefano Ceccherini{
179576e2bf8SStefano Ceccherini	// check if source is sharable - if so, share else clone
180688c1426SAxel Dörfler	if (string._IsShareable()) {
181576e2bf8SStefano Ceccherini		fPrivateData = string.fPrivateData;
182002b33b7SAxel Dörfler		atomic_add(&_ReferenceCount(), 1);
183002b33b7SAxel Dörfler			// string cannot go away right now
184576e2bf8SStefano Ceccherini	} else
185002b33b7SAxel Dörfler		_Init(string.String(), string.Length());
1869a82280aSStefano Ceccherini}
1879a82280aSStefano Ceccherini
1889a82280aSStefano Ceccherini
189576e2bf8SStefano CeccheriniBString::BString(const char* string, int32 maxLength)
190576e2bf8SStefano Ceccherini	: fPrivateData(NULL)
1919a82280aSStefano Ceccherini{
192576e2bf8SStefano Ceccherini	_Init(string, strlen_clamp(safestr(string), maxLength));
1939a82280aSStefano Ceccherini}
1949a82280aSStefano Ceccherini
1959a82280aSStefano Ceccherini
1969a82280aSStefano CeccheriniBString::~BString()
1979a82280aSStefano Ceccherini{
198002b33b7SAxel Dörfler	if (!_IsShareable() || atomic_add(&_ReferenceCount(), -1) == 1)
199002b33b7SAxel Dörfler		_FreePrivateData();
2009a82280aSStefano Ceccherini}
2019a82280aSStefano Ceccherini
2029a82280aSStefano Ceccherini
20343cca04aSAxel Dörfler//	#pragma mark - Access
204a8dee23eSStefano Ceccherini
205576e2bf8SStefano Ceccherini
2069a82280aSStefano Ceccheriniint32
2079a82280aSStefano CeccheriniBString::CountChars() const
2089a82280aSStefano Ceccherini{
209a5b7cbe3SMichael Lotz	return UTF8CountChars(fPrivateData, Length());
210a5b7cbe3SMichael Lotz}
211202ed890Sejakowatz
2127c830dc4SStefano Ceccherini
213a5b7cbe3SMichael Lotzint32
214a5b7cbe3SMichael LotzBString::CountBytes(int32 fromCharOffset, int32 charCount) const
215a5b7cbe3SMichael Lotz{
216a5b7cbe3SMichael Lotz	return UTF8CountBytes(
217a5b7cbe3SMichael Lotz		fPrivateData + UTF8CountBytes(fPrivateData, fromCharOffset), charCount);
2189a82280aSStefano Ceccherini}
2199a82280aSStefano Ceccherini
2209a82280aSStefano Ceccherini
2215a54e156SIngo Weinhold/*static*/ uint32
2225a54e156SIngo WeinholdBString::HashValue(const char* string)
2235a54e156SIngo Weinhold{
2245a54e156SIngo Weinhold	// from the Dragon Book: a slightly modified hashpjw()
2255a54e156SIngo Weinhold    uint32 h = 0;
2265a54e156SIngo Weinhold    if (string != NULL) {
2275a54e156SIngo Weinhold        for (; *string; string++) {
2285a54e156SIngo Weinhold            uint32 g = h & 0xf0000000;
2295a54e156SIngo Weinhold            if (g)
2305a54e156SIngo Weinhold                h ^= g >> 24;
2315a54e156SIngo Weinhold            h = (h << 4) + *string;
2325a54e156SIngo Weinhold        }
2335a54e156SIngo Weinhold    }
2345a54e156SIngo Weinhold    return h;
2355a54e156SIngo Weinhold}
2365a54e156SIngo Weinhold
2375a54e156SIngo Weinhold
23843cca04aSAxel Dörfler//	#pragma mark - Assignment
23943cca04aSAxel Dörfler
24043cca04aSAxel Dörfler
2419a82280aSStefano CeccheriniBString&
242576e2bf8SStefano CeccheriniBString::operator=(const BString& string)
2439a82280aSStefano Ceccherini{
244576e2bf8SStefano Ceccherini	return SetTo(string);
2459a82280aSStefano Ceccherini}
2469a82280aSStefano Ceccherini
2479a82280aSStefano Ceccherini
2489a82280aSStefano CeccheriniBString&
249576e2bf8SStefano CeccheriniBString::operator=(const char* string)
2509a82280aSStefano Ceccherini{
251534bebecSJérôme Duval	if (!string)
252534bebecSJérôme Duval		string = "";
253534bebecSJérôme Duval	if (string != String())
254576e2bf8SStefano Ceccherini		SetTo(string, strlen(string));
2559a82280aSStefano Ceccherini	return *this;
2569a82280aSStefano Ceccherini}
2579a82280aSStefano Ceccherini
2589a82280aSStefano Ceccherini
2599a82280aSStefano CeccheriniBString&
2609a82280aSStefano CeccheriniBString::operator=(char c)
2619a82280aSStefano Ceccherini{
262576e2bf8SStefano Ceccherini	return SetTo(c, 1);
2639a82280aSStefano Ceccherini}
2649a82280aSStefano Ceccherini
2659a82280aSStefano Ceccherini
2669a82280aSStefano CeccheriniBString&
267576e2bf8SStefano CeccheriniBString::SetTo(const char* string, int32 maxLength)
2689a82280aSStefano Ceccherini{
2698e3f5e89SFrançois Revol	if (maxLength < 0)
2708e3f5e89SFrançois Revol		maxLength = INT32_MAX;
271e52400cfSAxel Dörfler
272576e2bf8SStefano Ceccherini	maxLength = strlen_clamp(safestr(string), maxLength);
273e52400cfSAxel Dörfler
274e52400cfSAxel Dörfler	if (_MakeWritable(maxLength, false) == B_OK)
275576e2bf8SStefano Ceccherini		memcpy(fPrivateData, string, maxLength);
276e6a6424eSAxel Dörfler
2779a82280aSStefano Ceccherini	return *this;
2789a82280aSStefano Ceccherini}
2799a82280aSStefano Ceccherini
2809a82280aSStefano Ceccherini
2819a82280aSStefano CeccheriniBString&
282576e2bf8SStefano CeccheriniBString::SetTo(const BString& string)
2839a82280aSStefano Ceccherini{
284576e2bf8SStefano Ceccherini	// we share the information already
285576e2bf8SStefano Ceccherini	if (fPrivateData == string.fPrivateData)
286576e2bf8SStefano Ceccherini		return *this;
287576e2bf8SStefano Ceccherini
288002b33b7SAxel Dörfler	bool freeData = true;
289002b33b7SAxel Dörfler
290002b33b7SAxel Dörfler	if (_IsShareable() && atomic_add(&_ReferenceCount(), -1) > 1) {
291002b33b7SAxel Dörfler		// there is still someone who shares our data
292002b33b7SAxel Dörfler		freeData = false;
29343cca04aSAxel Dörfler	}
294576e2bf8SStefano Ceccherini
295002b33b7SAxel Dörfler	if (freeData)
296002b33b7SAxel Dörfler		_FreePrivateData();
297002b33b7SAxel Dörfler
298576e2bf8SStefano Ceccherini	// if source is sharable share, otherwise clone
299688c1426SAxel Dörfler	if (string._IsShareable()) {
300576e2bf8SStefano Ceccherini		fPrivateData = string.fPrivateData;
301002b33b7SAxel Dörfler		atomic_add(&_ReferenceCount(), 1);
302002b33b7SAxel Dörfler			// the string cannot go away right now
303576e2bf8SStefano Ceccherini	} else
304002b33b7SAxel Dörfler		_Init(string.String(), string.Length());
305576e2bf8SStefano Ceccherini
3069a82280aSStefano Ceccherini	return *this;
3079a82280aSStefano Ceccherini}
3089a82280aSStefano Ceccherini
3099a82280aSStefano Ceccherini
3109a82280aSStefano CeccheriniBString&
311576e2bf8SStefano CeccheriniBString::Adopt(BString& from)
3129a82280aSStefano Ceccherini{
313576e2bf8SStefano Ceccherini	SetTo(from);
314576e2bf8SStefano Ceccherini	from.SetTo("");
3157c830dc4SStefano Ceccherini
3169a82280aSStefano Ceccherini	return *this;
3179a82280aSStefano Ceccherini}
3189a82280aSStefano Ceccherini
3199a82280aSStefano Ceccherini
3209a82280aSStefano CeccheriniBString&
321576e2bf8SStefano CeccheriniBString::SetTo(const BString& string, int32 maxLength)
3229a82280aSStefano Ceccherini{
3238e3f5e89SFrançois Revol	if (maxLength < 0)
3248e3f5e89SFrançois Revol		maxLength = INT32_MAX;
325576e2bf8SStefano Ceccherini	if (fPrivateData != string.fPrivateData
326576e2bf8SStefano Ceccherini		// make sure we reassing in case length is different
327002b33b7SAxel Dörfler		|| (fPrivateData == string.fPrivateData && Length() > maxLength)) {
328002b33b7SAxel Dörfler		maxLength = min_clamp0(maxLength, string.Length());
329e52400cfSAxel Dörfler		if (_MakeWritable(maxLength, false) == B_OK)
330002b33b7SAxel Dörfler			memcpy(fPrivateData, string.String(), maxLength);
331576e2bf8SStefano Ceccherini	}
3329a82280aSStefano Ceccherini	return *this;
3339a82280aSStefano Ceccherini}
3349a82280aSStefano Ceccherini
3359a82280aSStefano Ceccherini
3369a82280aSStefano CeccheriniBString&
337576e2bf8SStefano CeccheriniBString::Adopt(BString& from, int32 maxLength)
3389a82280aSStefano Ceccherini{
339576e2bf8SStefano Ceccherini	SetTo(from, maxLength);
340576e2bf8SStefano Ceccherini	from.SetTo("");
3417c830dc4SStefano Ceccherini
3429a82280aSStefano Ceccherini	return *this;
3439a82280aSStefano Ceccherini}
3449a82280aSStefano Ceccherini
3459a82280aSStefano Ceccherini
3469a82280aSStefano CeccheriniBString&
3479a82280aSStefano CeccheriniBString::SetTo(char c, int32 count)
3489a82280aSStefano Ceccherini{
3495480b459SStefano Ceccherini	if (count < 0)
3505480b459SStefano Ceccherini		count = 0;
351576e2bf8SStefano Ceccherini
352e52400cfSAxel Dörfler	if (_MakeWritable(count, false) == B_OK)
35343cca04aSAxel Dörfler		memset(fPrivateData, c, count);
354820dca4dSJohn Scipione
355576e2bf8SStefano Ceccherini	return *this;
3569a82280aSStefano Ceccherini}
3579a82280aSStefano Ceccherini
3582ffca36aSStefano Ceccherini
359a5b7cbe3SMichael LotzBString&
360a5b7cbe3SMichael LotzBString::SetToChars(const char* string, int32 charCount)
361a5b7cbe3SMichael Lotz{
362a5b7cbe3SMichael Lotz	return SetTo(string, UTF8CountBytes(string, charCount));
363a5b7cbe3SMichael Lotz}
364a5b7cbe3SMichael Lotz
365a5b7cbe3SMichael Lotz
366a5b7cbe3SMichael LotzBString&
367a5b7cbe3SMichael LotzBString::SetToChars(const BString& string, int32 charCount)
368a5b7cbe3SMichael Lotz{
369a5b7cbe3SMichael Lotz	return SetTo(string, UTF8CountBytes(string.String(), charCount));
370a5b7cbe3SMichael Lotz}
371a5b7cbe3SMichael Lotz
372a5b7cbe3SMichael Lotz
373a5b7cbe3SMichael LotzBString&
374a5b7cbe3SMichael LotzBString::AdoptChars(BString& string, int32 charCount)
375a5b7cbe3SMichael Lotz{
376a5b7cbe3SMichael Lotz	return Adopt(string, UTF8CountBytes(string.String(), charCount));
377a5b7cbe3SMichael Lotz}
378a5b7cbe3SMichael Lotz
379a5b7cbe3SMichael Lotz
380c91c2de7SJonas SundströmBString&
381a29fb938SJonas SundströmBString::SetToFormat(const char* format, ...)
382c91c2de7SJonas Sundström{
383be3833c9SIngo Weinhold	va_list args;
384be3833c9SIngo Weinhold	va_start(args, format);
385be3833c9SIngo Weinhold	SetToFormatVarArgs(format, args);
386be3833c9SIngo Weinhold	va_end(args);
387be3833c9SIngo Weinhold
388be3833c9SIngo Weinhold	return *this;
389be3833c9SIngo Weinhold}
390be3833c9SIngo Weinhold
391be3833c9SIngo Weinhold
392be3833c9SIngo WeinholdBString&
393be3833c9SIngo WeinholdBString::SetToFormatVarArgs(const char* format, va_list args)
394be3833c9SIngo Weinhold{
395be3833c9SIngo Weinhold	// Use a small on-stack buffer to save a second vsnprintf() call for most
396be3833c9SIngo Weinhold	// use cases.
397146d274dSJonas Sundström	int32 bufferSize = 1024;
398146d274dSJonas Sundström	char buffer[bufferSize];
399a928c3f0SIngo Weinhold
400be3833c9SIngo Weinhold	va_list clonedArgs;
401be3833c9SIngo Weinhold#if __GNUC__ == 2
402be3833c9SIngo Weinhold	__va_copy(clonedArgs, args);
403be3833c9SIngo Weinhold#else
404be3833c9SIngo Weinhold	va_copy(clonedArgs, args);
405be3833c9SIngo Weinhold#endif
406be3833c9SIngo Weinhold	int32 bytes = vsnprintf(buffer, bufferSize, format, clonedArgs);
407be3833c9SIngo Weinhold	va_end(clonedArgs);
408146d274dSJonas Sundström
409146d274dSJonas Sundström	if (bytes < 0)
410146d274dSJonas Sundström		return Truncate(0);
411146d274dSJonas Sundström
412146d274dSJonas Sundström	if (bytes < bufferSize) {
413146d274dSJonas Sundström		SetTo(buffer);
414146d274dSJonas Sundström		return *this;
415c9e27adaSJonas Sundström	}
416146d274dSJonas Sundström
417be3833c9SIngo Weinhold	bytes = vsnprintf(LockBuffer(bytes), bytes + 1, format, args);
418146d274dSJonas Sundström	if (bytes < 0)
419146d274dSJonas Sundström		bytes = 0;
420146d274dSJonas Sundström
421146d274dSJonas Sundström	UnlockBuffer(bytes);
422c91c2de7SJonas Sundström	return *this;
423c91c2de7SJonas Sundström}
424c91c2de7SJonas Sundström
425c91c2de7SJonas Sundström
4263fe7b3f7SMichael Lotzint
4273fe7b3f7SMichael LotzBString::ScanWithFormat(const char* format, ...)
4283fe7b3f7SMichael Lotz{
4293fe7b3f7SMichael Lotz	va_list args;
4303fe7b3f7SMichael Lotz	va_start(args, format);
4313fe7b3f7SMichael Lotz	int result = ScanWithFormatVarArgs(format, args);
4323fe7b3f7SMichael Lotz	va_end(args);
4333fe7b3f7SMichael Lotz
4343fe7b3f7SMichael Lotz	return result;
4353fe7b3f7SMichael Lotz}
4363fe7b3f7SMichael Lotz
4373fe7b3f7SMichael Lotz
4383fe7b3f7SMichael Lotzint
4393fe7b3f7SMichael LotzBString::ScanWithFormatVarArgs(const char* format, va_list args)
4403fe7b3f7SMichael Lotz{
4413fe7b3f7SMichael Lotz	return vsscanf(fPrivateData, format, args);
4423fe7b3f7SMichael Lotz}
4433fe7b3f7SMichael Lotz
4443fe7b3f7SMichael Lotz
44543cca04aSAxel Dörfler//	#pragma mark - Substring copying
44643cca04aSAxel Dörfler
447a8dee23eSStefano Ceccherini
448576e2bf8SStefano CeccheriniBString&
449688c1426SAxel DörflerBString::CopyInto(BString& into, int32 fromOffset, int32 length) const
4507c830dc4SStefano Ceccherini{
451576e2bf8SStefano Ceccherini	if (this != &into)
452576e2bf8SStefano Ceccherini		into.SetTo(fPrivateData + fromOffset, length);
4537c830dc4SStefano Ceccherini	return into;
4547c830dc4SStefano Ceccherini}
4557c830dc4SStefano Ceccherini
4567c830dc4SStefano Ceccherini
4579a82280aSStefano Ceccherinivoid
458576e2bf8SStefano CeccheriniBString::CopyInto(char* into, int32 fromOffset, int32 length) const
4599a82280aSStefano Ceccherini{
460576e2bf8SStefano Ceccherini	if (into) {
461576e2bf8SStefano Ceccherini		length = min_clamp0(length, Length() - fromOffset);
462576e2bf8SStefano Ceccherini		memcpy(into, fPrivateData + fromOffset, length);
4637c830dc4SStefano Ceccherini	}
4649a82280aSStefano Ceccherini}
4659a82280aSStefano Ceccherini
4669a82280aSStefano Ceccherini
467a5b7cbe3SMichael LotzBString&
468a5b7cbe3SMichael LotzBString::CopyCharsInto(BString& into, int32 fromCharOffset,
469a5b7cbe3SMichael Lotz	int32 charCount) const
470a5b7cbe3SMichael Lotz{
471a5b7cbe3SMichael Lotz	int32 fromOffset = UTF8CountBytes(fPrivateData, fromCharOffset);
472a5b7cbe3SMichael Lotz	int32 length = UTF8CountBytes(fPrivateData + fromOffset, charCount);
473a5b7cbe3SMichael Lotz	return CopyInto(into, fromOffset, length);
474a5b7cbe3SMichael Lotz}
475a5b7cbe3SMichael Lotz
476a5b7cbe3SMichael Lotz
477a5b7cbe3SMichael Lotzbool
478a5b7cbe3SMichael LotzBString::CopyCharsInto(char* into, int32* intoLength, int32 fromCharOffset,
479a5b7cbe3SMichael Lotz	int32 charCount) const
480a5b7cbe3SMichael Lotz{
481a5b7cbe3SMichael Lotz	if (into == NULL)
482a5b7cbe3SMichael Lotz		return false;
483a5b7cbe3SMichael Lotz
484a5b7cbe3SMichael Lotz	int32 fromOffset = UTF8CountBytes(fPrivateData, fromCharOffset);
485a5b7cbe3SMichael Lotz	int32 length = UTF8CountBytes(fPrivateData + fromOffset, charCount);
486a5b7cbe3SMichael Lotz	length = min_clamp0(length, Length() - fromOffset);
487a5b7cbe3SMichael Lotz
488a5b7cbe3SMichael Lotz	if (intoLength != NULL) {
489a5b7cbe3SMichael Lotz		if (*intoLength < length)
490a5b7cbe3SMichael Lotz			return false;
491a5b7cbe3SMichael Lotz		*intoLength = length;
492a5b7cbe3SMichael Lotz	}
493a5b7cbe3SMichael Lotz
494a5b7cbe3SMichael Lotz	memcpy(into, fPrivateData + fromOffset, length);
495a5b7cbe3SMichael Lotz	return true;
496a5b7cbe3SMichael Lotz}
497a5b7cbe3SMichael Lotz
498a5b7cbe3SMichael Lotz
499c82776b2SIngo Weinholdbool
500c82776b2SIngo WeinholdBString::Split(const char* separator, bool noEmptyStrings,
501c82776b2SIngo Weinhold	BStringList& _list) const
502c82776b2SIngo Weinhold{
503c82776b2SIngo Weinhold	int32 separatorLength = strlen(separator);
504c82776b2SIngo Weinhold	int32 length = Length();
505c82776b2SIngo Weinhold	if (separatorLength == 0 || length == 0 || separatorLength > length) {
506c82776b2SIngo Weinhold		if (length == 0 && noEmptyStrings)
507c82776b2SIngo Weinhold			return true;
508c82776b2SIngo Weinhold		return _list.Add(*this);
509c82776b2SIngo Weinhold	}
510c82776b2SIngo Weinhold
511c82776b2SIngo Weinhold	int32 index = 0;
512c82776b2SIngo Weinhold	for (;;) {
513c82776b2SIngo Weinhold		int32 endIndex = index < length ? FindFirst(separator, index) : length;
514c82776b2SIngo Weinhold		if (endIndex < 0)
515c82776b2SIngo Weinhold			endIndex = length;
516c82776b2SIngo Weinhold
517c82776b2SIngo Weinhold		if (endIndex > index || !noEmptyStrings) {
518c82776b2SIngo Weinhold			BString toAppend(String() + index, endIndex - index);
519c82776b2SIngo Weinhold			if (toAppend.Length() != endIndex - index
5201c521f0bSIngo Weinhold				|| !_list.Add(toAppend)) {
521c82776b2SIngo Weinhold				return false;
522c82776b2SIngo Weinhold			}
523c82776b2SIngo Weinhold		}
524c82776b2SIngo Weinhold
525c82776b2SIngo Weinhold		if (endIndex == length)
526c82776b2SIngo Weinhold			break;
527c82776b2SIngo Weinhold
528a25f7264SJérôme Duval		index = endIndex + separatorLength;
529c82776b2SIngo Weinhold	}
530c82776b2SIngo Weinhold
531c82776b2SIngo Weinhold	return true;
532c82776b2SIngo Weinhold}
533c82776b2SIngo Weinhold
534c82776b2SIngo Weinhold
53543cca04aSAxel Dörfler//	#pragma mark - Appending
53643cca04aSAxel Dörfler
53743cca04aSAxel Dörfler
5389a82280aSStefano CeccheriniBString&
539576e2bf8SStefano CeccheriniBString::operator+=(const char* string)
5409a82280aSStefano Ceccherini{
5412cbb2916SStephan Aßmus	if (string) {
5422cbb2916SStephan Aßmus		int32 length = strlen(string);
5432cbb2916SStephan Aßmus		if (length > 0)
5442cbb2916SStephan Aßmus			_DoAppend(string, length);
5452cbb2916SStephan Aßmus	}
5469a82280aSStefano Ceccherini	return *this;
5479a82280aSStefano Ceccherini}
5489a82280aSStefano Ceccherini
5499a82280aSStefano Ceccherini
5509a82280aSStefano CeccheriniBString&
5519a82280aSStefano CeccheriniBString::operator+=(char c)
5529a82280aSStefano Ceccherini{
5535480b459SStefano Ceccherini	_DoAppend(&c, 1);
5549a82280aSStefano Ceccherini	return *this;
5559a82280aSStefano Ceccherini}
5569a82280aSStefano Ceccherini
5579a82280aSStefano Ceccherini
5589a82280aSStefano CeccheriniBString&
559576e2bf8SStefano CeccheriniBString::Append(const BString& string, int32 length)
5609a82280aSStefano Ceccherini{
5612cbb2916SStephan Aßmus	if (&string != this) {
562f9745144SIngo Weinhold		length = min_clamp0(length, string.Length());
5632cbb2916SStephan Aßmus		if (length > 0)
5642cbb2916SStephan Aßmus			_DoAppend(string.fPrivateData, length);
5652cbb2916SStephan Aßmus	}
5669a82280aSStefano Ceccherini	return *this;
5679a82280aSStefano Ceccherini}
5689a82280aSStefano Ceccherini
5699a82280aSStefano Ceccherini
5709a82280aSStefano CeccheriniBString&
571576e2bf8SStefano CeccheriniBString::Append(const char* string, int32 length)
5729a82280aSStefano Ceccherini{
5732cbb2916SStephan Aßmus	if (string) {
574f9745144SIngo Weinhold		length = strlen_clamp(string, length);
5752cbb2916SStephan Aßmus		if (length > 0)
5762cbb2916SStephan Aßmus			_DoAppend(string, length);
5772cbb2916SStephan Aßmus	}
5789a82280aSStefano Ceccherini	return *this;
5799a82280aSStefano Ceccherini}
5809a82280aSStefano Ceccherini
5819a82280aSStefano Ceccherini
5829a82280aSStefano CeccheriniBString&
5839a82280aSStefano CeccheriniBString::Append(char c, int32 count)
5849a82280aSStefano Ceccherini{
5852cbb2916SStephan Aßmus	int32 oldLength = Length();
586576e2bf8SStefano Ceccherini	if (count > 0 && _DoAppend("", count))
5872cbb2916SStephan Aßmus		memset(fPrivateData + oldLength, c, count);
5889a82280aSStefano Ceccherini	return *this;
5899a82280aSStefano Ceccherini}
5909a82280aSStefano Ceccherini
5919a82280aSStefano Ceccherini
592a5b7cbe3SMichael LotzBString&
593a5b7cbe3SMichael LotzBString::AppendChars(const BString& string, int32 charCount)
594a5b7cbe3SMichael Lotz{
595a5b7cbe3SMichael Lotz	return Append(string, UTF8CountBytes(string.String(), charCount));
596a5b7cbe3SMichael Lotz}
597a5b7cbe3SMichael Lotz
598a5b7cbe3SMichael Lotz
599a5b7cbe3SMichael LotzBString&
600a5b7cbe3SMichael LotzBString::AppendChars(const char* string, int32 charCount)
601a5b7cbe3SMichael Lotz{
602a5b7cbe3SMichael Lotz	return Append(string, UTF8CountBytes(string, charCount));
603a5b7cbe3SMichael Lotz}
604a5b7cbe3SMichael Lotz
605a5b7cbe3SMichael Lotz
606e6a6424eSAxel Dörfler//	#pragma mark - Prepending
607e6a6424eSAxel Dörfler
608e6a6424eSAxel Dörfler
6099a82280aSStefano CeccheriniBString&
610576e2bf8SStefano CeccheriniBString::Prepend(const char* string)
6119a82280aSStefano Ceccherini{
612576e2bf8SStefano Ceccherini	if (string)
613576e2bf8SStefano Ceccherini		_DoPrepend(string, strlen(string));
6149a82280aSStefano Ceccherini	return *this;
6159a82280aSStefano Ceccherini}
6169a82280aSStefano Ceccherini
6179a82280aSStefano Ceccherini
6189a82280aSStefano CeccheriniBString&
619576e2bf8SStefano CeccheriniBString::Prepend(const BString& string)
6209a82280aSStefano Ceccherini{
6217c58a468SAxel Dörfler	if (&string != this)
6227c58a468SAxel Dörfler		_DoPrepend(string.String(), string.Length());
6239a82280aSStefano Ceccherini	return *this;
6249a82280aSStefano Ceccherini}
6259a82280aSStefano Ceccherini
6269a82280aSStefano Ceccherini
6279a82280aSStefano CeccheriniBString&
628576e2bf8SStefano CeccheriniBString::Prepend(const char* string, int32 length)
6299a82280aSStefano Ceccherini{
630576e2bf8SStefano Ceccherini	if (string)
631576e2bf8SStefano Ceccherini		_DoPrepend(string, strlen_clamp(string, length));
6329a82280aSStefano Ceccherini	return *this;
6339a82280aSStefano Ceccherini}
6349a82280aSStefano Ceccherini
6359a82280aSStefano Ceccherini
6369a82280aSStefano CeccheriniBString&
637576e2bf8SStefano CeccheriniBString::Prepend(const BString& string, int32 length)
6389a82280aSStefano Ceccherini{
6397c58a468SAxel Dörfler	if (&string != this)
640576e2bf8SStefano Ceccherini		_DoPrepend(string.fPrivateData, min_clamp0(length, string.Length()));
6419a82280aSStefano Ceccherini	return *this;
6429a82280aSStefano Ceccherini}
6439a82280aSStefano Ceccherini
6449a82280aSStefano Ceccherini
6459a82280aSStefano CeccheriniBString&
6469a82280aSStefano CeccheriniBString::Prepend(char c, int32 count)
6479a82280aSStefano Ceccherini{
648576e2bf8SStefano Ceccherini	if (count > 0 && _DoPrepend("", count))
64943cca04aSAxel Dörfler		memset(fPrivateData, c, count);
6509a82280aSStefano Ceccherini	return *this;
6519a82280aSStefano Ceccherini}
6529a82280aSStefano Ceccherini
6539a82280aSStefano Ceccherini
654a5b7cbe3SMichael LotzBString&
655a5b7cbe3SMichael LotzBString::PrependChars(const char* string, int32 charCount)
656a5b7cbe3SMichael Lotz{
657a5b7cbe3SMichael Lotz	return Prepend(string, UTF8CountBytes(string, charCount));
658a5b7cbe3SMichael Lotz}
659a5b7cbe3SMichael Lotz
660a5b7cbe3SMichael Lotz
661a5b7cbe3SMichael LotzBString&
662a5b7cbe3SMichael LotzBString::PrependChars(const BString& string, int32 charCount)
663a5b7cbe3SMichael Lotz{
664a5b7cbe3SMichael Lotz	return Prepend(string, UTF8CountBytes(string.String(), charCount));
665a5b7cbe3SMichael Lotz}
666a5b7cbe3SMichael Lotz
667a5b7cbe3SMichael Lotz
668e6a6424eSAxel Dörfler//	#pragma mark - Inserting
669e6a6424eSAxel Dörfler
670e6a6424eSAxel Dörfler
6717c830dc4SStefano CeccheriniBString&
672576e2bf8SStefano CeccheriniBString::Insert(const char* string, int32 position)
6737c830dc4SStefano Ceccherini{
674e52400cfSAxel Dörfler	if (string != NULL && position <= Length()) {
675576e2bf8SStefano Ceccherini		int32 len = int32(strlen(string));
676576e2bf8SStefano Ceccherini		if (position < 0) {
677576e2bf8SStefano Ceccherini			int32 skipLen = min_clamp0(-1 * position, len);
678576e2bf8SStefano Ceccherini			string += skipLen;
6795480b459SStefano Ceccherini			len -= skipLen;
680576e2bf8SStefano Ceccherini			position = 0;
681576e2bf8SStefano Ceccherini		} else {
682576e2bf8SStefano Ceccherini			position = min_clamp0(position, Length());
683576e2bf8SStefano Ceccherini		}
684576e2bf8SStefano Ceccherini		_DoInsert(string, position, len);
6857c830dc4SStefano Ceccherini	}
6867c830dc4SStefano Ceccherini	return *this;
6877c830dc4SStefano Ceccherini}
6887c830dc4SStefano Ceccherini
6897c830dc4SStefano Ceccherini
6907c830dc4SStefano CeccheriniBString&
691576e2bf8SStefano CeccheriniBString::Insert(const char* string, int32 length, int32 position)
6927c830dc4SStefano Ceccherini{
693e52400cfSAxel Dörfler	if (string != NULL && position <= Length()) {
694576e2bf8SStefano Ceccherini		int32 len = strlen_clamp(string, length);
695576e2bf8SStefano Ceccherini		if (position < 0) {
696576e2bf8SStefano Ceccherini			int32 skipLen = min_clamp0(-1 * position, len);
697576e2bf8SStefano Ceccherini			string += skipLen;
6985480b459SStefano Ceccherini			len -= skipLen;
699576e2bf8SStefano Ceccherini			position = 0;
700576e2bf8SStefano Ceccherini		} else {
701576e2bf8SStefano Ceccherini			position = min_clamp0(position, Length());
702576e2bf8SStefano Ceccherini		}
703576e2bf8SStefano Ceccherini		_DoInsert(string, position, len);
7047c830dc4SStefano Ceccherini	}
7057c830dc4SStefano Ceccherini	return *this;
7067c830dc4SStefano Ceccherini}
7077c830dc4SStefano Ceccherini
7087c830dc4SStefano Ceccherini
7097c830dc4SStefano CeccheriniBString&
710576e2bf8SStefano CeccheriniBString::Insert(const char* string, int32 fromOffset, int32 length,
711688c1426SAxel Dörfler	int32 position)
7127c830dc4SStefano Ceccherini{
713576e2bf8SStefano Ceccherini	if (string)
714576e2bf8SStefano Ceccherini		Insert(string + fromOffset, length, position);
715576e2bf8SStefano Ceccherini	return *this;
7167c830dc4SStefano Ceccherini}
7177c830dc4SStefano Ceccherini
7187c830dc4SStefano Ceccherini
7197c830dc4SStefano CeccheriniBString&
720576e2bf8SStefano CeccheriniBString::Insert(const BString& string, int32 position)
7217c830dc4SStefano Ceccherini{
7227c58a468SAxel Dörfler	if (&string != this && string.Length() > 0)
723576e2bf8SStefano Ceccherini		Insert(string.fPrivateData, position);
724576e2bf8SStefano Ceccherini	return *this;
7257c830dc4SStefano Ceccherini}
7267c830dc4SStefano Ceccherini
7277c830dc4SStefano Ceccherini
7287c830dc4SStefano CeccheriniBString&
729688c1426SAxel DörflerBString::Insert(const BString& string, int32 length, int32 position)
7307c830dc4SStefano Ceccherini{
7317c58a468SAxel Dörfler	if (&string != this && string.Length() > 0)
732576e2bf8SStefano Ceccherini		Insert(string.String(), length, position);
7337c830dc4SStefano Ceccherini	return *this;
7347c830dc4SStefano Ceccherini}
7357c830dc4SStefano Ceccherini
7367c830dc4SStefano Ceccherini
7377c830dc4SStefano CeccheriniBString&
738688c1426SAxel DörflerBString::Insert(const BString& string, int32 fromOffset, int32 length,
739688c1426SAxel Dörfler	int32 position)
7407c830dc4SStefano Ceccherini{
7417c58a468SAxel Dörfler	if (&string != this && string.Length() > 0)
742576e2bf8SStefano Ceccherini		Insert(string.String() + fromOffset, length, position);
7437c830dc4SStefano Ceccherini	return *this;
7447c830dc4SStefano Ceccherini}
7457c830dc4SStefano Ceccherini
7467c830dc4SStefano Ceccherini
7477c830dc4SStefano CeccheriniBString&
748576e2bf8SStefano CeccheriniBString::Insert(char c, int32 count, int32 position)
7497c830dc4SStefano Ceccherini{
750576e2bf8SStefano Ceccherini	if (position < 0) {
751576e2bf8SStefano Ceccherini		count = MAX(count + position, 0);
752576e2bf8SStefano Ceccherini		position = 0;
7535480b459SStefano Ceccherini	} else
754576e2bf8SStefano Ceccherini		position = min_clamp0(position, Length());
755576e2bf8SStefano Ceccherini
756576e2bf8SStefano Ceccherini	if (count > 0 && _DoInsert("", position, count))
757576e2bf8SStefano Ceccherini		memset(fPrivateData + position, c, count);
758576e2bf8SStefano Ceccherini
7597c830dc4SStefano Ceccherini	return *this;
7607c830dc4SStefano Ceccherini}
7617c830dc4SStefano Ceccherini
7627c830dc4SStefano Ceccherini
763a5b7cbe3SMichael LotzBString&
764a5b7cbe3SMichael LotzBString::InsertChars(const char* string, int32 charPosition)
765a5b7cbe3SMichael Lotz{
766a5b7cbe3SMichael Lotz	return Insert(string, UTF8CountBytes(fPrivateData, charPosition));
767a5b7cbe3SMichael Lotz}
768a5b7cbe3SMichael Lotz
769a5b7cbe3SMichael Lotz
770a5b7cbe3SMichael LotzBString&
771a5b7cbe3SMichael LotzBString::InsertChars(const char* string, int32 charCount, int32 charPosition)
772a5b7cbe3SMichael Lotz{
773a5b7cbe3SMichael Lotz	return Insert(string, UTF8CountBytes(string, charCount),
774a5b7cbe3SMichael Lotz		UTF8CountBytes(fPrivateData, charPosition));
775a5b7cbe3SMichael Lotz}
776a5b7cbe3SMichael Lotz
777a5b7cbe3SMichael Lotz
778a5b7cbe3SMichael LotzBString&
779a5b7cbe3SMichael LotzBString::InsertChars(const char* string, int32 fromCharOffset,
780a5b7cbe3SMichael Lotz	int32 charCount, int32 charPosition)
781a5b7cbe3SMichael Lotz{
782a5b7cbe3SMichael Lotz	int32 fromOffset = UTF8CountBytes(string, fromCharOffset);
783a5b7cbe3SMichael Lotz	return Insert(string, fromOffset,
784a5b7cbe3SMichael Lotz		UTF8CountBytes(string + fromOffset, charCount),
785a5b7cbe3SMichael Lotz		UTF8CountBytes(fPrivateData, charPosition));
786a5b7cbe3SMichael Lotz}
787a5b7cbe3SMichael Lotz
788a5b7cbe3SMichael Lotz
789a5b7cbe3SMichael LotzBString&
790a5b7cbe3SMichael LotzBString::InsertChars(const BString& string, int32 charPosition)
791a5b7cbe3SMichael Lotz{
792a5b7cbe3SMichael Lotz	return Insert(string, UTF8CountBytes(fPrivateData, charPosition));
793a5b7cbe3SMichael Lotz}
794a5b7cbe3SMichael Lotz
795a5b7cbe3SMichael Lotz
796a5b7cbe3SMichael LotzBString&
797a5b7cbe3SMichael LotzBString::InsertChars(const BString& string, int32 charCount, int32 charPosition)
798a5b7cbe3SMichael Lotz{
799a5b7cbe3SMichael Lotz	return Insert(string, UTF8CountBytes(string.String(), charCount),
800a5b7cbe3SMichael Lotz		UTF8CountBytes(fPrivateData, charPosition));
801a5b7cbe3SMichael Lotz}
802a5b7cbe3SMichael Lotz
803a5b7cbe3SMichael Lotz
804a5b7cbe3SMichael LotzBString&
805a5b7cbe3SMichael LotzBString::InsertChars(const BString& string, int32 fromCharOffset,
806