VirtualBox

source: vbox/trunk/src/VBox/Runtime/common/string/ministring.cpp@ 67650

最後變更 在這個檔案從67650是 67650,由 vboxsync 提交於 8 年 前

IPRT: Added const char * variant of RTCString::contains.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 14.3 KB
 
1/* $Id: ministring.cpp 67650 2017-06-27 16:55:17Z vboxsync $ */
2/** @file
3 * IPRT - Mini C++ string class.
4 *
5 * This is a base for both Utf8Str and other places where IPRT may want to use
6 * a lean C++ string class.
7 */
8
9/*
10 * Copyright (C) 2007-2016 Oracle Corporation
11 *
12 * This file is part of VirtualBox Open Source Edition (OSE), as
13 * available from http://www.alldomusa.eu.org. This file is free software;
14 * you can redistribute it and/or modify it under the terms of the GNU
15 * General Public License (GPL) as published by the Free Software
16 * Foundation, in version 2 as it comes in the "COPYING" file of the
17 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
18 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
19 *
20 * The contents of this file may alternatively be used under the terms
21 * of the Common Development and Distribution License Version 1.0
22 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
23 * VirtualBox OSE distribution, in which case the provisions of the
24 * CDDL are applicable instead of those of the GPL.
25 *
26 * You may elect to license modified versions of this file under the
27 * terms and conditions of either the GPL or the CDDL or both.
28 */
29
30
31/*********************************************************************************************************************************
32* Header Files *
33*********************************************************************************************************************************/
34#include <iprt/cpp/ministring.h>
35
36
37/*********************************************************************************************************************************
38* Global Variables *
39*********************************************************************************************************************************/
40const size_t RTCString::npos = ~(size_t)0;
41
42
43/*********************************************************************************************************************************
44* Defined Constants And Macros *
45*********************************************************************************************************************************/
46/** Allocation block alignment used when appending bytes to a string. */
47#define IPRT_MINISTRING_APPEND_ALIGNMENT 64
48
49
50RTCString &RTCString::printf(const char *pszFormat, ...)
51{
52 va_list va;
53 va_start(va, pszFormat);
54 printfV(pszFormat, va);
55 va_end(va);
56 return *this;
57}
58
59/**
60 * Callback used with RTStrFormatV by RTCString::printfV.
61 *
62 * @returns The number of bytes added (not used).
63 *
64 * @param pvArg The string object.
65 * @param pachChars The characters to append.
66 * @param cbChars The number of characters. 0 on the final callback.
67 */
68/*static*/ DECLCALLBACK(size_t)
69RTCString::printfOutputCallback(void *pvArg, const char *pachChars, size_t cbChars)
70{
71 RTCString *pThis = (RTCString *)pvArg;
72 if (cbChars)
73 {
74 size_t cchBoth = pThis->m_cch + cbChars;
75 if (cchBoth >= pThis->m_cbAllocated)
76 {
77 /* Double the buffer size, if it's less that _4M. Align sizes like
78 for append. */
79 size_t cbAlloc = RT_ALIGN_Z(pThis->m_cbAllocated, IPRT_MINISTRING_APPEND_ALIGNMENT);
80 cbAlloc += RT_MIN(cbAlloc, _4M);
81 if (cbAlloc <= cchBoth)
82 cbAlloc = RT_ALIGN_Z(cchBoth + 1, IPRT_MINISTRING_APPEND_ALIGNMENT);
83 pThis->reserve(cbAlloc);
84#ifndef RT_EXCEPTIONS_ENABLED
85 AssertReleaseReturn(pThis->capacity() > cchBoth, 0);
86#endif
87 }
88
89 memcpy(&pThis->m_psz[pThis->m_cch], pachChars, cbChars);
90 pThis->m_cch = cchBoth;
91 pThis->m_psz[cchBoth] = '\0';
92 }
93 return cbChars;
94}
95
96RTCString &RTCString::printfV(const char *pszFormat, va_list va)
97{
98 cleanup();
99 RTStrFormatV(printfOutputCallback, this, NULL, NULL, pszFormat, va);
100 return *this;
101}
102
103RTCString &RTCString::append(const RTCString &that)
104{
105 size_t cchThat = that.length();
106 if (cchThat)
107 {
108 size_t cchThis = length();
109 size_t cchBoth = cchThis + cchThat;
110
111 if (cchBoth >= m_cbAllocated)
112 {
113 reserve(RT_ALIGN_Z(cchBoth + 1, IPRT_MINISTRING_APPEND_ALIGNMENT));
114 // calls realloc(cchBoth + 1) and sets m_cbAllocated; may throw bad_alloc.
115#ifndef RT_EXCEPTIONS_ENABLED
116 AssertRelease(capacity() > cchBoth);
117#endif
118 }
119
120 memcpy(m_psz + cchThis, that.m_psz, cchThat);
121 m_psz[cchBoth] = '\0';
122 m_cch = cchBoth;
123 }
124 return *this;
125}
126
127RTCString &RTCString::append(const char *pszThat)
128{
129 size_t cchThat = strlen(pszThat);
130 if (cchThat)
131 {
132 size_t cchThis = length();
133 size_t cchBoth = cchThis + cchThat;
134
135 if (cchBoth >= m_cbAllocated)
136 {
137 reserve(RT_ALIGN_Z(cchBoth + 1, IPRT_MINISTRING_APPEND_ALIGNMENT));
138 // calls realloc(cchBoth + 1) and sets m_cbAllocated; may throw bad_alloc.
139#ifndef RT_EXCEPTIONS_ENABLED
140 AssertRelease(capacity() > cchBoth);
141#endif
142 }
143
144 memcpy(&m_psz[cchThis], pszThat, cchThat);
145 m_psz[cchBoth] = '\0';
146 m_cch = cchBoth;
147 }
148 return *this;
149}
150
151RTCString& RTCString::append(char ch)
152{
153 Assert((unsigned char)ch < 0x80); /* Don't create invalid UTF-8. */
154 if (ch)
155 {
156 // allocate in chunks of 20 in case this gets called several times
157 if (m_cch + 1 >= m_cbAllocated)
158 {
159 reserve(RT_ALIGN_Z(m_cch + 2, IPRT_MINISTRING_APPEND_ALIGNMENT));
160 // calls realloc(cbBoth) and sets m_cbAllocated; may throw bad_alloc.
161#ifndef RT_EXCEPTIONS_ENABLED
162 AssertRelease(capacity() > m_cch + 1);
163#endif
164 }
165
166 m_psz[m_cch] = ch;
167 m_psz[++m_cch] = '\0';
168 }
169 return *this;
170}
171
172RTCString &RTCString::appendCodePoint(RTUNICP uc)
173{
174 /*
175 * Single byte encoding.
176 */
177 if (uc < 0x80)
178 return RTCString::append((char)uc);
179
180 /*
181 * Multibyte encoding.
182 * Assume max encoding length when resizing the string, that's simpler.
183 */
184 AssertReturn(uc <= UINT32_C(0x7fffffff), *this);
185
186 if (m_cch + 6 >= m_cbAllocated)
187 {
188 reserve(RT_ALIGN_Z(m_cch + 6 + 1, IPRT_MINISTRING_APPEND_ALIGNMENT));
189 // calls realloc(cbBoth) and sets m_cbAllocated; may throw bad_alloc.
190#ifndef RT_EXCEPTIONS_ENABLED
191 AssertRelease(capacity() > m_cch + 6);
192#endif
193 }
194
195 char *pszNext = RTStrPutCp(&m_psz[m_cch], uc);
196 m_cch = pszNext - m_psz;
197 *pszNext = '\0';
198
199 return *this;
200}
201
202size_t RTCString::find(const char *pszNeedle, size_t offStart /*= 0*/) const
203{
204 if (offStart < length())
205 {
206 const char *pszThis = c_str();
207 if (pszThis)
208 {
209 if (pszNeedle && *pszNeedle != '\0')
210 {
211 const char *pszHit = strstr(pszThis + offStart, pszNeedle);
212 if (pszHit)
213 return pszHit - pszThis;
214 }
215 }
216 }
217
218 return npos;
219}
220
221size_t RTCString::find(const RTCString *pStrNeedle, size_t offStart /*= 0*/) const
222{
223 if (offStart < length())
224 {
225 const char *pszThis = c_str();
226 if (pszThis)
227 {
228 if (pStrNeedle)
229 {
230 const char *pszNeedle = pStrNeedle->c_str();
231 if (pszNeedle && *pszNeedle != '\0')
232 {
233 const char *pszHit = strstr(pszThis + offStart, pszNeedle);
234 if (pszHit)
235 return pszHit - pszThis;
236 }
237 }
238 }
239 }
240
241 return npos;
242}
243
244void RTCString::findReplace(char chFind, char chReplace)
245{
246 Assert((unsigned int)chFind < 128U);
247 Assert((unsigned int)chReplace < 128U);
248
249 for (size_t i = 0; i < length(); ++i)
250 {
251 char *p = &m_psz[i];
252 if (*p == chFind)
253 *p = chReplace;
254 }
255}
256
257size_t RTCString::count(char ch) const
258{
259 Assert((unsigned int)ch < 128U);
260
261 size_t c = 0;
262 const char *psz = m_psz;
263 if (psz)
264 {
265 char chCur;
266 while ((chCur = *psz++) != '\0')
267 if (chCur == ch)
268 c++;
269 }
270 return c;
271}
272
273#if 0 /** @todo implement these when needed. */
274size_t RTCString::count(const char *psz, CaseSensitivity cs = CaseSensitive) const
275{
276}
277
278size_t RTCString::count(const RTCString *pStr, CaseSensitivity cs = CaseSensitive) const
279{
280
281}
282#endif
283
284RTCString RTCString::substrCP(size_t pos /*= 0*/, size_t n /*= npos*/) const
285{
286 RTCString ret;
287
288 if (n)
289 {
290 const char *psz;
291
292 if ((psz = c_str()))
293 {
294 RTUNICP cp;
295
296 // walk the UTF-8 characters until where the caller wants to start
297 size_t i = pos;
298 while (*psz && i--)
299 if (RT_FAILURE(RTStrGetCpEx(&psz, &cp)))
300 return ret; // return empty string on bad encoding
301
302 const char *pFirst = psz;
303
304 if (n == npos)
305 // all the rest:
306 ret = pFirst;
307 else
308 {
309 i = n;
310 while (*psz && i--)
311 if (RT_FAILURE(RTStrGetCpEx(&psz, &cp)))
312 return ret; // return empty string on bad encoding
313
314 size_t cbCopy = psz - pFirst;
315 if (cbCopy)
316 {
317 ret.reserve(cbCopy + 1); // may throw bad_alloc
318#ifndef RT_EXCEPTIONS_ENABLED
319 AssertRelease(capacity() >= cbCopy + 1);
320#endif
321 memcpy(ret.m_psz, pFirst, cbCopy);
322 ret.m_cch = cbCopy;
323 ret.m_psz[cbCopy] = '\0';
324 }
325 }
326 }
327 }
328
329 return ret;
330}
331
332bool RTCString::endsWith(const RTCString &that, CaseSensitivity cs /*= CaseSensitive*/) const
333{
334 size_t l1 = length();
335 if (l1 == 0)
336 return false;
337
338 size_t l2 = that.length();
339 if (l1 < l2)
340 return false;
341 /** @todo r=bird: If l2 is 0, then m_psz can be NULL and we will crash. See
342 * also handling of l2 == in startsWith. */
343
344 size_t l = l1 - l2;
345 if (cs == CaseSensitive)
346 return ::RTStrCmp(&m_psz[l], that.m_psz) == 0;
347 return ::RTStrICmp(&m_psz[l], that.m_psz) == 0;
348}
349
350bool RTCString::startsWith(const RTCString &that, CaseSensitivity cs /*= CaseSensitive*/) const
351{
352 size_t l1 = length();
353 size_t l2 = that.length();
354 if (l1 == 0 || l2 == 0) /** @todo r=bird: this differs from endsWith, and I think other IPRT code. If l2 == 0, it matches anything. */
355 return false;
356
357 if (l1 < l2)
358 return false;
359
360 if (cs == CaseSensitive)
361 return ::RTStrNCmp(m_psz, that.m_psz, l2) == 0;
362 return ::RTStrNICmp(m_psz, that.m_psz, l2) == 0;
363}
364
365bool RTCString::contains(const RTCString &that, CaseSensitivity cs /*= CaseSensitive*/) const
366{
367 /** @todo r-bird: Not checking for NULL strings like startsWith does (and
368 * endsWith only does half way). */
369 if (cs == CaseSensitive)
370 return ::RTStrStr(m_psz, that.m_psz) != NULL;
371 return ::RTStrIStr(m_psz, that.m_psz) != NULL;
372}
373
374bool RTCString::contains(const char *pszNeedle, CaseSensitivity cs /*= CaseSensitive*/) const
375{
376 /** @todo r-bird: Not checking for NULL strings like startsWith does (and
377 * endsWith only does half way). */
378 if (cs == CaseSensitive)
379 return ::RTStrStr(m_psz, pszNeedle) != NULL;
380 return ::RTStrIStr(m_psz, pszNeedle) != NULL;
381}
382
383int RTCString::toInt(uint64_t &i) const
384{
385 if (!m_psz)
386 return VERR_NO_DIGITS;
387 return RTStrToUInt64Ex(m_psz, NULL, 0, &i);
388}
389
390int RTCString::toInt(uint32_t &i) const
391{
392 if (!m_psz)
393 return VERR_NO_DIGITS;
394 return RTStrToUInt32Ex(m_psz, NULL, 0, &i);
395}
396
397RTCList<RTCString, RTCString *>
398RTCString::split(const RTCString &a_rstrSep, SplitMode mode /* = RemoveEmptyParts */) const
399{
400 RTCList<RTCString> strRet;
401 if (!m_psz)
402 return strRet;
403 if (a_rstrSep.isEmpty())
404 {
405 strRet.append(RTCString(m_psz));
406 return strRet;
407 }
408
409 size_t cch = m_cch;
410 char const *pszTmp = m_psz;
411 while (cch > 0)
412 {
413 char const *pszNext = strstr(pszTmp, a_rstrSep.c_str());
414 if (!pszNext)
415 {
416 strRet.append(RTCString(pszTmp, cch));
417 break;
418 }
419 size_t cchNext = pszNext - pszTmp;
420 if ( cchNext > 0
421 || mode == KeepEmptyParts)
422 strRet.append(RTCString(pszTmp, cchNext));
423 pszTmp += cchNext + a_rstrSep.length();
424 cch -= cchNext + a_rstrSep.length();
425 }
426
427 return strRet;
428}
429
430/* static */
431RTCString
432RTCString::joinEx(const RTCList<RTCString, RTCString *> &a_rList,
433 const RTCString &a_rstrPrefix /* = "" */,
434 const RTCString &a_rstrSep /* = "" */)
435{
436 RTCString strRet;
437 if (a_rList.size() > 1)
438 {
439 /* calc the required size */
440 size_t cbNeeded = a_rstrSep.length() * (a_rList.size() - 1) + 1;
441 cbNeeded += a_rstrPrefix.length() * (a_rList.size() - 1) + 1;
442 for (size_t i = 0; i < a_rList.size(); ++i)
443 cbNeeded += a_rList.at(i).length();
444 strRet.reserve(cbNeeded);
445
446 /* do the appending. */
447 for (size_t i = 0; i < a_rList.size() - 1; ++i)
448 {
449 if (a_rstrPrefix.isNotEmpty())
450 strRet.append(a_rstrPrefix);
451 strRet.append(a_rList.at(i));
452 strRet.append(a_rstrSep);
453 }
454 strRet.append(a_rList.last());
455 }
456 /* special case: one list item. */
457 else if (a_rList.size() > 0)
458 {
459 if (a_rstrPrefix.isNotEmpty())
460 strRet.append(a_rstrPrefix);
461 strRet.append(a_rList.last());
462 }
463
464 return strRet;
465}
466
467/* static */
468RTCString
469RTCString::join(const RTCList<RTCString, RTCString *> &a_rList,
470 const RTCString &a_rstrSep /* = "" */)
471{
472 return RTCString::joinEx(a_rList,
473 "" /* a_rstrPrefix */, a_rstrSep);
474}
475
476const RTCString operator+(const RTCString &a_rStr1, const RTCString &a_rStr2)
477{
478 RTCString strRet(a_rStr1);
479 strRet += a_rStr2;
480 return strRet;
481}
482
483const RTCString operator+(const RTCString &a_rStr1, const char *a_pszStr2)
484{
485 RTCString strRet(a_rStr1);
486 strRet += a_pszStr2;
487 return strRet;
488}
489
490const RTCString operator+(const char *a_psz1, const RTCString &a_rStr2)
491{
492 RTCString strRet(a_psz1);
493 strRet += a_rStr2;
494 return strRet;
495}
496
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette