Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/icucommon/charstr.cpp
12343 views
1
// © 2016 and later: Unicode, Inc. and others.
2
// License & terms of use: http://www.unicode.org/copyright.html
3
/*
4
*******************************************************************************
5
* Copyright (C) 2010-2015, International Business Machines
6
* Corporation and others. All Rights Reserved.
7
*******************************************************************************
8
* file name: charstr.cpp
9
* encoding: UTF-8
10
* tab size: 8 (not used)
11
* indentation:4
12
*
13
* created on: 2010may19
14
* created by: Markus W. Scherer
15
*/
16
17
#include <cstdlib>
18
19
#include "unicode/utypes.h"
20
#include "unicode/putil.h"
21
#include "charstr.h"
22
#include "cmemory.h"
23
#include "cstring.h"
24
#include "uinvchar.h"
25
#include "ustr_imp.h"
26
27
U_NAMESPACE_BEGIN
28
29
CharString::CharString(CharString&& src) U_NOEXCEPT
30
: buffer(std::move(src.buffer)), len(src.len) {
31
src.len = 0; // not strictly necessary because we make no guarantees on the source string
32
}
33
34
CharString& CharString::operator=(CharString&& src) U_NOEXCEPT {
35
buffer = std::move(src.buffer);
36
len = src.len;
37
src.len = 0; // not strictly necessary because we make no guarantees on the source string
38
return *this;
39
}
40
41
char *CharString::cloneData(UErrorCode &errorCode) const {
42
if (U_FAILURE(errorCode)) { return nullptr; }
43
char *p = static_cast<char *>(uprv_malloc(len + 1));
44
if (p == nullptr) {
45
errorCode = U_MEMORY_ALLOCATION_ERROR;
46
return nullptr;
47
}
48
uprv_memcpy(p, buffer.getAlias(), len + 1);
49
return p;
50
}
51
52
int32_t CharString::extract(char *dest, int32_t capacity, UErrorCode &errorCode) const {
53
if (U_FAILURE(errorCode)) { return len; }
54
if (capacity < 0 || (capacity > 0 && dest == nullptr)) {
55
errorCode = U_ILLEGAL_ARGUMENT_ERROR;
56
return len;
57
}
58
const char *src = buffer.getAlias();
59
if (0 < len && len <= capacity && src != dest) {
60
uprv_memcpy(dest, src, len);
61
}
62
return u_terminateChars(dest, capacity, len, &errorCode);
63
}
64
65
CharString &CharString::copyFrom(const CharString &s, UErrorCode &errorCode) {
66
if(U_SUCCESS(errorCode) && this!=&s && ensureCapacity(s.len+1, 0, errorCode)) {
67
len=s.len;
68
uprv_memcpy(buffer.getAlias(), s.buffer.getAlias(), len+1);
69
}
70
return *this;
71
}
72
73
int32_t CharString::lastIndexOf(char c) const {
74
for(int32_t i=len; i>0;) {
75
if(buffer[--i]==c) {
76
return i;
77
}
78
}
79
return -1;
80
}
81
82
bool CharString::contains(StringPiece s) const {
83
if (s.empty()) { return false; }
84
const char *p = buffer.getAlias();
85
int32_t lastStart = len - s.length();
86
for (int32_t i = 0; i <= lastStart; ++i) {
87
if (uprv_memcmp(p + i, s.data(), s.length()) == 0) {
88
return true;
89
}
90
}
91
return false;
92
}
93
94
CharString &CharString::truncate(int32_t newLength) {
95
if(newLength<0) {
96
newLength=0;
97
}
98
if(newLength<len) {
99
buffer[len=newLength]=0;
100
}
101
return *this;
102
}
103
104
CharString &CharString::append(char c, UErrorCode &errorCode) {
105
if(ensureCapacity(len+2, 0, errorCode)) {
106
buffer[len++]=c;
107
buffer[len]=0;
108
}
109
return *this;
110
}
111
112
CharString &CharString::append(const char *s, int32_t sLength, UErrorCode &errorCode) {
113
if(U_FAILURE(errorCode)) {
114
return *this;
115
}
116
if(sLength<-1 || (s==NULL && sLength!=0)) {
117
errorCode=U_ILLEGAL_ARGUMENT_ERROR;
118
return *this;
119
}
120
if(sLength<0) {
121
sLength= static_cast<int32_t>(uprv_strlen(s));
122
}
123
if(sLength>0) {
124
if(s==(buffer.getAlias()+len)) {
125
// The caller wrote into the getAppendBuffer().
126
if(sLength>=(buffer.getCapacity()-len)) {
127
// The caller wrote too much.
128
errorCode=U_INTERNAL_PROGRAM_ERROR;
129
} else {
130
buffer[len+=sLength]=0;
131
}
132
} else if(buffer.getAlias()<=s && s<(buffer.getAlias()+len) &&
133
sLength>=(buffer.getCapacity()-len)
134
) {
135
// (Part of) this string is appended to itself which requires reallocation,
136
// so we have to make a copy of the substring and append that.
137
return append(CharString(s, sLength, errorCode), errorCode);
138
} else if(ensureCapacity(len+sLength+1, 0, errorCode)) {
139
uprv_memcpy(buffer.getAlias()+len, s, sLength);
140
buffer[len+=sLength]=0;
141
}
142
}
143
return *this;
144
}
145
146
CharString &CharString::appendNumber(int32_t number, UErrorCode &status) {
147
if (number < 0) {
148
this->append('-', status);
149
if (U_FAILURE(status)) {
150
return *this;
151
}
152
}
153
154
if (number == 0) {
155
this->append('0', status);
156
return *this;
157
}
158
159
int32_t numLen = 0;
160
while (number != 0) {
161
int32_t residue = number % 10;
162
number /= 10;
163
this->append(std::abs(residue) + '0', status);
164
numLen++;
165
if (U_FAILURE(status)) {
166
return *this;
167
}
168
}
169
170
int32_t start = this->length() - numLen, end = this->length() - 1;
171
while(start < end) {
172
std::swap(this->data()[start++], this->data()[end--]);
173
}
174
175
return *this;
176
}
177
178
char *CharString::getAppendBuffer(int32_t minCapacity,
179
int32_t desiredCapacityHint,
180
int32_t &resultCapacity,
181
UErrorCode &errorCode) {
182
if(U_FAILURE(errorCode)) {
183
resultCapacity=0;
184
return NULL;
185
}
186
int32_t appendCapacity=buffer.getCapacity()-len-1; // -1 for NUL
187
if(appendCapacity>=minCapacity) {
188
resultCapacity=appendCapacity;
189
return buffer.getAlias()+len;
190
}
191
if(ensureCapacity(len+minCapacity+1, len+desiredCapacityHint+1, errorCode)) {
192
resultCapacity=buffer.getCapacity()-len-1;
193
return buffer.getAlias()+len;
194
}
195
resultCapacity=0;
196
return NULL;
197
}
198
199
CharString &CharString::appendInvariantChars(const UnicodeString &s, UErrorCode &errorCode) {
200
return appendInvariantChars(s.getBuffer(), s.length(), errorCode);
201
}
202
203
CharString &CharString::appendInvariantChars(const UChar* uchars, int32_t ucharsLen, UErrorCode &errorCode) {
204
if(U_FAILURE(errorCode)) {
205
return *this;
206
}
207
if (!uprv_isInvariantUString(uchars, ucharsLen)) {
208
errorCode = U_INVARIANT_CONVERSION_ERROR;
209
return *this;
210
}
211
if(ensureCapacity(len+ucharsLen+1, 0, errorCode)) {
212
u_UCharsToChars(uchars, buffer.getAlias()+len, ucharsLen);
213
len += ucharsLen;
214
buffer[len] = 0;
215
}
216
return *this;
217
}
218
219
UBool CharString::ensureCapacity(int32_t capacity,
220
int32_t desiredCapacityHint,
221
UErrorCode &errorCode) {
222
if(U_FAILURE(errorCode)) {
223
return false;
224
}
225
if(capacity>buffer.getCapacity()) {
226
if(desiredCapacityHint==0) {
227
desiredCapacityHint=capacity+buffer.getCapacity();
228
}
229
if( (desiredCapacityHint<=capacity || buffer.resize(desiredCapacityHint, len+1)==NULL) &&
230
buffer.resize(capacity, len+1)==NULL
231
) {
232
errorCode=U_MEMORY_ALLOCATION_ERROR;
233
return false;
234
}
235
}
236
return true;
237
}
238
239
CharString &CharString::appendPathPart(StringPiece s, UErrorCode &errorCode) {
240
if(U_FAILURE(errorCode)) {
241
return *this;
242
}
243
if(s.length()==0) {
244
return *this;
245
}
246
char c;
247
if(len>0 && (c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
248
append(getDirSepChar(), errorCode);
249
}
250
append(s, errorCode);
251
return *this;
252
}
253
254
CharString &CharString::ensureEndsWithFileSeparator(UErrorCode &errorCode) {
255
char c;
256
if(U_SUCCESS(errorCode) && len>0 &&
257
(c=buffer[len-1])!=U_FILE_SEP_CHAR && c!=U_FILE_ALT_SEP_CHAR) {
258
append(getDirSepChar(), errorCode);
259
}
260
return *this;
261
}
262
263
char CharString::getDirSepChar() const {
264
char dirSepChar = U_FILE_SEP_CHAR;
265
#if (U_FILE_SEP_CHAR != U_FILE_ALT_SEP_CHAR)
266
// We may need to return a different directory separator when building for Cygwin or MSYS2.
267
if(len>0 && !uprv_strchr(data(), U_FILE_SEP_CHAR) && uprv_strchr(data(), U_FILE_ALT_SEP_CHAR))
268
dirSepChar = U_FILE_ALT_SEP_CHAR;
269
#endif
270
return dirSepChar;
271
}
272
273
U_NAMESPACE_END
274
275