• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include "common_components/base/c_string.h"
16 #include "common_components/log/log.h"
17 
18 #include <libgen.h>
19 
20 namespace common {
21 // The last two characters are units, such as "kb" or "ms".
22 constexpr int8_t LAST_CHARACTERS_SIZE = 2;
23 // nDecimal = ceil(sizeof(int32_t) * 8 * log(2)) = ceil(2.41 * sizeof(int32_t))
24 // consider overhead for sign & '\0' and alignment, replace 2.41 by 4
25 constexpr int8_t MIN_ALIGN_SPACE = 4;
26 
CString()27 CString::CString()
28 {
29     str_ = reinterpret_cast<char*>(malloc(capacity_));
30     LOGF_IF(str_ == nullptr) << "CString::Init failed";
31     *str_ = '\0';
32     length_ = 0;
33 }
34 
CString(const char * initStr)35 CString::CString(const char* initStr)
36 {
37     if (initStr != nullptr) {
38         size_t initLen = strlen(initStr);
39         while (capacity_ < initLen + 1) {
40             capacity_ <<= 1;
41         }
42         str_ = reinterpret_cast<char*>(malloc(capacity_));
43         LOGF_IF(str_ == nullptr) << "CString::Init failed";
44         if (*initStr != '\0') {
45             LOGF_IF(memcpy_s(str_, capacity_, initStr, initLen) != EOK) << "CString::CString memcpy_s failed";
46         }
47         length_ = initLen;
48         str_[length_] = '\0';
49     }
50 }
51 
CString(char c)52 CString::CString(char c)
53 {
54     str_ = reinterpret_cast<char*>(malloc(capacity_));
55     LOGF_IF(str_ == nullptr) << "CString::Init failed";
56     str_[0] = c;
57     str_[1] = '\0';
58     length_ = 1;
59 }
60 
61 // nDecimal = ceil(sizeof(int32_t) * 8 * log(2)) = ceil(2.41 * sizeof(int32_t))
62 // consider overhead for sign & '\0' and alignment, replace 2.41 by 4
CString(int32_t number)63 CString::CString(int32_t number)
64 {
65     capacity_ = sizeof(int32_t) * MIN_ALIGN_SPACE;
66     str_ = reinterpret_cast<char*>(malloc(capacity_));
67     LOGF_IF(str_ == nullptr) << "CString::Init failed";
68     int ret = sprintf_s(str_, capacity_, "%d", number);
69     LOGF_IF(ret == -1) << "CString::Init failed";
70     length_ = static_cast<size_t>(ret);
71 }
72 
CString(int64_t number)73 CString::CString(int64_t number)
74 {
75     capacity_ = sizeof(int64_t) * MIN_ALIGN_SPACE;
76     str_ = reinterpret_cast<char*>(malloc(capacity_));
77     LOGF_IF(str_ == nullptr) << "CString::Init failed";
78     int ret = sprintf_s(str_, capacity_, "%lld", number);
79     LOGF_IF(ret == -1) << "CString::Init failed";
80     length_ = static_cast<size_t>(ret);
81 }
82 
CString(uint32_t number)83 CString::CString(uint32_t number)
84 {
85     capacity_ = sizeof(uint32_t) * MIN_ALIGN_SPACE;
86     str_ = reinterpret_cast<char*>(malloc(capacity_));
87     LOGF_IF(str_ == nullptr) << "CString::Init failed";
88     int ret = sprintf_s(str_, capacity_, "%u", number);
89     LOGF_IF(ret == -1) << "CString::Init failed";
90     length_ = static_cast<size_t>(ret);
91 }
92 
CString(uint64_t number)93 CString::CString(uint64_t number)
94 {
95     capacity_ = sizeof(uint64_t) * MIN_ALIGN_SPACE;
96     str_ = reinterpret_cast<char*>(malloc(capacity_));
97     LOGF_IF(str_ == nullptr) << "CString::Init failed";
98     int ret = sprintf_s(str_, capacity_, "%lu", number);
99     LOGF_IF(ret == -1) << "CString::Init failed";
100     length_ = static_cast<size_t>(ret);
101 }
102 
CString(const CString & other)103 CString::CString(const CString& other)
104 {
105     size_t initLen = other.Length();
106     while (capacity_ < initLen + 1) {
107         capacity_ <<= 1;
108     }
109     str_ = reinterpret_cast<char*>(malloc(capacity_));
110     LOGF_IF(str_ == nullptr) << "CString::Init failed";
111     if (!other.IsEmpty()) {
112         LOGF_IF(memcpy_s(str_, capacity_, other.Str(), initLen) != EOK) << "CString::CString memcpy_s failed";
113     }
114     length_ = initLen;
115     str_[length_] = '\0';
116 }
117 
CString(size_t number,char ch)118 CString::CString(size_t number, char ch)
119 {
120     while (capacity_ < number + 1) {
121         capacity_ <<= 1;
122     }
123     str_ = reinterpret_cast<char*>(malloc(capacity_));
124     LOGF_IF(str_ == nullptr) << "CString::Init failed";
125     LOGF_IF(memset_s(str_, capacity_, ch, number) != EOK) << "CString::CString memset_s failed";
126     length_ = number;
127     str_[length_] = '\0';
128 }
129 
operator =(const CString & other)130 CString& CString::operator=(const CString& other)
131 {
132     if (this == &other) {
133         return *this;
134     }
135     size_t initLen = other.Length();
136     while (capacity_ < initLen + 1) {
137         capacity_ <<= 1;
138     }
139     if (str_ != nullptr) {
140         free(str_);
141     }
142     str_ = reinterpret_cast<char*>(malloc(capacity_));
143     LOGF_IF(str_ == nullptr) << "CString::operator= malloc failed";
144     if (!other.IsEmpty()) {
145         LOGF_IF(memcpy_s(str_, capacity_, other.Str(), initLen) != EOK) << "CString::operator= memcpy_s failed";
146     }
147     length_ = initLen;
148     str_[length_] = '\0';
149     return *this;
150 }
151 
~CString()152 CString::~CString()
153 {
154     if (str_ != nullptr) {
155         free(str_);
156         str_ = nullptr;
157     }
158 }
159 
operator [](size_t index) const160 const char& CString::operator[](size_t index) const
161 {
162     if (index >= length_) {
163         LOG_COMMON(FATAL) << "CString[index] failed index=" << index;
164     }
165     return str_[index];
166 }
167 
operator [](size_t index)168 char& CString::operator[](size_t index)
169 {
170     if (index >= length_) {
171         LOG_COMMON(FATAL) << "CString[index] failed index=" << index;
172     }
173     return str_[index];
174 }
175 
EnsureSpace(size_t addLen)176 void CString::EnsureSpace(size_t addLen)
177 {
178     if (addLen == 0 || capacity_ >= length_ + addLen + 1) {
179         return;
180     }
181     while (capacity_ < length_ + addLen + 1) {
182         capacity_ <<= 1;
183     }
184     char* newStr = reinterpret_cast<char*>(malloc(capacity_));
185     LOGF_IF(newStr == nullptr) << "CString::Init failed";
186     LOGF_IF(memcpy_s(newStr, capacity_, str_, length_) != EOK) << "CString::EnsureSpace memcpy_s failed";
187     if (str_ != nullptr) {
188         free(str_);
189     }
190     str_ = newStr;
191 }
192 
Append(const CString & addStr,size_t addLen)193 CString& CString::Append(const CString& addStr, size_t addLen)
194 {
195     if (addStr.IsEmpty()) {
196         return *this;
197     }
198     if (addLen == 0) {
199         addLen = strlen(addStr.str_);
200     }
201     EnsureSpace(addLen);
202     DCHECK_CC(addLen <= addStr.length_);
203     LOGF_IF(memcpy_s(str_ + length_, capacity_ - length_, addStr.str_, addLen) != EOK) <<
204         "CString::Append memcpy_s failed";
205     length_ += addLen;
206     DCHECK_CC(str_ != nullptr);
207     str_[length_] = '\0';
208     return *this;
209 }
210 
Append(const char * addStr,size_t addLen)211 CString& CString::Append(const char* addStr, size_t addLen)
212 {
213     if (addStr == nullptr || *addStr == '\0') {
214         return *this;
215     }
216     if (addLen == 0) {
217         addLen = strlen(addStr);
218     }
219     EnsureSpace(addLen);
220     DCHECK_CC(addLen <= strlen(addStr));
221     LOGF_IF(memcpy_s(str_ + length_, capacity_ - length_, addStr, addLen) != EOK) <<
222         "CString::Append memcpy_s failed";
223     length_ += addLen;
224     str_[length_] = '\0';
225     return *this;
226 }
227 
Combine(const char * addStr) const228 CString CString::Combine(const char* addStr) const
229 {
230     CString newStr;
231     newStr.Append(*this);
232     newStr.Append(addStr);
233     return newStr;
234 }
235 
Combine(const CString & addStr) const236 CString CString::Combine(const CString& addStr) const
237 {
238     CString newStr;
239     newStr.Append(*this);
240     newStr.Append(addStr);
241     return newStr;
242 }
243 
Length() const244 size_t CString::Length() const { return length_; }
245 
Str() const246 const char* CString::Str() const noexcept { return str_; }
247 
GetStr() const248 char* CString::GetStr() const noexcept { return str_; }
249 
Truncate(size_t index)250 CString& CString::Truncate(size_t index)
251 {
252     if (index >= length_) {
253         LOG_COMMON(ERROR) << "CString::Truncate input parameter error";
254         return *this;
255     }
256     length_ = index;
257     str_[index] = '\0';
258     return *this;
259 }
260 
Insert(size_t index,const char * addStr)261 CString& CString::Insert(size_t index, const char* addStr)
262 {
263     if (index >= length_ || *addStr == '\0') {
264         LOG_COMMON(ERROR) << "CString::Insert input parameter error";
265         return *this;
266     }
267     CString subStr = SubStr(index);
268     Truncate(index);
269     Append(addStr);
270     Append(subStr);
271     return *this;
272 }
273 
Find(const char * subStr,size_t begin) const274 int CString::Find(const char* subStr, size_t begin) const
275 {
276     if (begin >= length_) {
277         LOG_COMMON(ERROR) << "CString::Find input parameter error";
278         return -1;
279     }
280     char* ret = strstr(str_ + begin, subStr);
281     return ret != nullptr ? ret - str_ : -1;
282 }
283 
Find(const char subStr,size_t begin) const284 int CString::Find(const char subStr, size_t begin) const
285 {
286     if (begin >= length_) {
287         LOG_COMMON(ERROR) << "CString::Find input parameter error";
288         return -1;
289     }
290     char* ret = strchr(str_ + begin, subStr);
291     return ret != nullptr ? ret - str_ : -1;
292 }
293 
RFind(const char * subStr) const294 int CString::RFind(const char* subStr) const
295 {
296     int index = -1;
297     int ret = Find(subStr);
298     while (ret != -1) {
299         index = ret;
300         if (ret + strlen(subStr) == length_) {
301             break;
302         }
303         ret = Find(subStr, ret + strlen(subStr));
304     }
305     return index;
306 }
307 
SubStr(size_t index,size_t len) const308 CString CString::SubStr(size_t index, size_t len) const
309 {
310     CString newStr;
311     if (index + len > length_) {
312         LOG_COMMON(ERROR) << "CString::SubStr input parameter error\n";
313         return newStr;
314     }
315     newStr.EnsureSpace(len);
316     if (memcpy_s(newStr.str_, newStr.capacity_, str_ + index, len) != EOK) {
317         LOG_COMMON(ERROR) << "CString::SubStr memcpy_s failed";
318         return newStr;
319     }
320     newStr.length_ = len;
321     DCHECK_CC(newStr.str_ != nullptr);
322     newStr.str_[newStr.length_] = '\0';
323     return newStr;
324 }
325 
SubStr(size_t index) const326 CString CString::SubStr(size_t index) const
327 {
328     if (index >= length_) {
329         LOG_COMMON(ERROR) << "CString::SubStr input parameter error\n";
330         return CString();
331     }
332     return SubStr(index, length_ - index);
333 }
334 
Split(CString & source,char separator)335 std::vector<CString> CString::Split(CString& source, char separator)
336 {
337     std::vector<CString> tokens;
338     const char s[2] = { separator, '\0' };
339     char* tmpSave = nullptr;
340 
341     CString tmp = source;
342     CString token = strtok_s(tmp.str_, s, &tmpSave);
343     while (!token.IsEmpty()) {
344         tokens.push_back(token);
345         token = strtok_s(nullptr, s, &tmpSave);
346     }
347     return tokens;
348 }
349 
BaseName(const CString & path)350 char* CString::BaseName(const CString& path) { return basename(path.str_); }
351 
352 // helpers for logging one line with no more than 256 characters
FormatString(const char * format,...)353 CString CString::FormatString(const char* format, ...)
354 {
355     constexpr size_t defaultBufferSize = 256;
356     char buf[defaultBufferSize];
357 
358     va_list argList;
359     va_start(argList, format);
360     if (vsprintf_s(buf, sizeof(buf), format, argList) == -1) {
361         return "invalid arguments for FormatString";
362     }
363     va_end(argList);
364 
365     return CString(buf);
366 }
367 
368 // Check whether `s` can convert to a positive number.
IsPosNumber(const CString & s)369 bool CString::IsPosNumber(const CString& s)
370 {
371     if (s.Length() == 0 || s == "+" || s == "0") {
372         return false;
373     }
374     size_t i = 0;
375     char it = s.Str()[i];
376     if (it == '+') {
377         i++;
378     }
379     for (; i < s.Length(); ++i) {
380         it = s.Str()[i];
381         if (it < '0' || it > '9') {
382             return false;
383         }
384     }
385     return true;
386 }
IsPosDecimal(const CString & s)387 bool CString::IsPosDecimal(const CString& s)
388 {
389     if (s.Length() == 0 || s == "+" || s == "0") {
390         return false;
391     }
392     char* endptr;
393     double number = std::strtod(s.str_, &endptr);
394     if (*endptr != '\0') {
395         return false;
396     }
397     if (number > 0) {
398         return true;
399     }
400     return false;
401 }
402 // Check whether `s` can convert to a number.
IsNumber(const CString & s)403 bool CString::IsNumber(const CString& s)
404 {
405     if (s.Length() == 0) {
406         return false;
407     }
408     size_t i = 0;
409     char it = s.Str()[i];
410     if (it == '-') {
411         i++;
412     }
413     for (; i < s.Length(); ++i) {
414         it = s.Str()[i];
415         if (it < '0' || it > '9') {
416             return false;
417         }
418     }
419     return true;
420 }
421 
422 // If `s` is "1" or "true" or "TRUE", return true.
423 // Otherwise return false.
ParseFlagFromEnv(const CString & s)424 bool CString::ParseFlagFromEnv(const CString& s) { return s == "1" || s == "true" || s == "TRUE"; }
425 
RemoveBlankSpace() const426 CString CString::RemoveBlankSpace() const
427 {
428     size_t index = 0;
429     CString noBlankSpaceStr(this->Str());
430     if (length_ == 0) {
431         return noBlankSpaceStr;
432     }
433     DCHECK_CC(noBlankSpaceStr.str_ != nullptr);
434     for (size_t i = 0; i < length_; i++) {
435         if (str_[i] != ' ') {
436             noBlankSpaceStr.str_[index++] = str_[i];
437         }
438     }
439     noBlankSpaceStr.str_[index] = '\0';
440     noBlankSpaceStr.length_ = index;
441     return noBlankSpaceStr;
442 }
443 
ParseSizeFromEnv(const CString & env)444 size_t CString::ParseSizeFromEnv(const CString& env)
445 {
446     size_t tempSize = 0;
447     CString noBlankStr = env.RemoveBlankSpace();
448     size_t len = noBlankStr.Length();
449     if (len <= LAST_CHARACTERS_SIZE) {
450         return 0;
451     }
452     // Split size and unit.
453     CString num = noBlankStr.SubStr(0, len - 2);
454     CString unit = noBlankStr.SubStr(len - 2, 2);
455 
456     if (IsPosNumber(num)) {
457         tempSize = std::strtoul(num.Str(), nullptr, 0);
458     } else {
459         return 0;
460     }
461 
462     unit.ToLowerCase();
463 
464     if (unit == "kb") {
465         return tempSize;
466     } else if (unit == "mb") {
467         tempSize *= 1024; // unit: 1024 * 1KB = 1MB
468     } else if (unit == "gb") {
469         tempSize *= 1024UL * 1024; // unit: 1024 * 1024 * 1KB = 1GB
470     } else {
471         return 0;
472     }
473 
474     return tempSize;
475 }
476 
ParseTimeFromEnv(const CString & env)477 size_t CString::ParseTimeFromEnv(const CString& env)
478 {
479     size_t tempTime = 0;
480     CString noBlankStr = env.RemoveBlankSpace();
481     size_t len = noBlankStr.Length();
482     if (len <= 1) { // The last one characters are units, such as "s".
483         return 0;
484     }
485     // Split size and unit.
486     CString num = noBlankStr.SubStr(0, len - 1);
487     CString unit = noBlankStr.SubStr(len - 1, 1);
488     if (unit == "s" && IsPosNumber(num)) {
489         tempTime = std::strtoul(num.Str(), nullptr, 0);
490         tempTime *= 1000UL * 1000 * 1000; // unit: 1000 * 1000 * 1000 * 1ns= 1s
491         return tempTime;
492     }
493     num = noBlankStr.SubStr(0, len - LAST_CHARACTERS_SIZE); // The last two characters are units, such as "ms".
494     unit = noBlankStr.SubStr(len - LAST_CHARACTERS_SIZE, LAST_CHARACTERS_SIZE);
495     if (IsPosNumber(num)) {
496         tempTime = std::strtoul(num.Str(), nullptr, 0);
497     } else {
498         return 0;
499     }
500     unit.ToLowerCase();
501     if (unit == "ns") {
502         return tempTime;
503     } else if (unit == "us") {
504         tempTime *= 1000; // unit: 1000 *  1ns= 1us
505     } else if (unit == "ms") {
506         tempTime *= 1000 * 1000; // unit: 1000 * 1000 *  1ns= 1ms
507     } else {
508         return 0;
509     }
510 
511     return tempTime;
512 }
513 
ParseNumFromEnv(const CString & env)514 int CString::ParseNumFromEnv(const CString& env)
515 {
516     int temp = 0;
517     CString noBlankStr = env.RemoveBlankSpace();
518     if (IsNumber(noBlankStr)) {
519         temp = std::atoi(noBlankStr.Str());
520     } else {
521         return 0;
522     }
523 
524     return temp;
525 }
526 
ParsePosNumFromEnv(const CString & env)527 size_t CString::ParsePosNumFromEnv(const CString& env)
528 {
529     size_t temp = 0;
530     CString noBlankStr = env.RemoveBlankSpace();
531     if (IsPosNumber(noBlankStr)) {
532         temp = static_cast<size_t>(std::atoi(noBlankStr.Str()));
533     } else {
534         return 0;
535     }
536 
537     return temp;
538 }
539 
ParsePosDecFromEnv(const CString & env)540 double CString::ParsePosDecFromEnv(const CString& env)
541 {
542     double temp = 0;
543     CString noBlankStr = env.RemoveBlankSpace();
544     if (IsPosDecimal(noBlankStr)) {
545         temp = std::atof(noBlankStr.Str());
546     } else {
547         return 0;
548     }
549     return temp;
550 }
551 
Replace(size_t pos,CString cStr)552 void CString::Replace(size_t pos, CString cStr)
553 {
554     size_t repLen = cStr.Length();
555     LOGF_IF(pos + repLen > length_) << "CString::Replace failed, input is too long";
556     LOGF_IF(memcpy_s(str_ + pos, repLen, cStr.Str(), repLen) != EOK) << "CString::Replace memcpy_s failed";
557 }
558 
ReplaceAll(CString replacement,CString target)559 void CString::ReplaceAll(CString replacement, CString target)
560 {
561     int index = -1;
562     int ret = Find(target.Str());
563     while (ret != -1) {
564         index = ret;
565         Replace(index, replacement);
566         ret = Find(target.Str(), ret + target.length_);
567     }
568     return;
569 }
570 
571 } // namespace common
572