Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
m2mstring.cpp
00001 /* 00002 * Copyright (c) 2015 ARM Limited. All rights reserved. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * Licensed under the Apache License, Version 2.0 (the License); you may 00005 * not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an AS IS BASIS, WITHOUT 00012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 #include "mbed-client/m2mstring.h" 00017 #include <string.h> // strlen 00018 #include <stdlib.h> // malloc, realloc 00019 #include <assert.h> 00020 00021 namespace m2m { 00022 00023 00024 // can't use std::min as it is not universally available 00025 #ifndef MIN 00026 #define MIN(A,B) ((A) < (B) ? (A) : (B)) 00027 #endif 00028 00029 const String::size_type String::npos = static_cast<size_t>(-1); 00030 00031 char* String::strdup(const char* s) 00032 { 00033 const size_t len = strlen(s)+1; 00034 char *p2 = static_cast<char*>(malloc(len)); 00035 if (p2) { 00036 memcpy(p2, s, len); 00037 allocated_ = len; 00038 size_ = len-1; 00039 } 00040 return p2; 00041 } 00042 00043 String::String() 00044 : p( strdup("") ) 00045 { 00046 } 00047 00048 String::~String() 00049 { 00050 free(p); 00051 p = 0; 00052 } 00053 00054 String::String(const String& s) 00055 : p(0) 00056 { 00057 p = static_cast<char*>(malloc(s.size_ + 1)); 00058 00059 allocated_ = s.size_ + 1; 00060 size_ = s.size_; 00061 memcpy(p, s.p, size_ + 1); 00062 } 00063 00064 String::String(const char* s) 00065 : p(strdup(s)) 00066 { 00067 } 00068 00069 String::String(const char* str, size_t n) 00070 { 00071 p = static_cast<char*>(malloc(n + 1)); 00072 00073 allocated_ = n + 1; 00074 size_ = n; 00075 memcpy(p, str, n); 00076 p[n] = 0; 00077 } 00078 00079 String& String::operator=(const char* s) 00080 { 00081 if ( p != s ) { 00082 // s could point into our own string, so we have to allocate a new string 00083 const size_t len = strlen(s); 00084 char* copy = (char*) malloc( len + 1); 00085 memmove(copy, s, len+1); // trailing 0 00086 free( p ); 00087 p = copy; 00088 size_ = len; 00089 allocated_ = len+1; 00090 } 00091 return *this; 00092 } 00093 00094 String& String::operator=(const String& s) 00095 { 00096 return operator=(s.p); 00097 } 00098 00099 String& String::operator+=(const String& s) 00100 { 00101 if (s.size_ > 0) { 00102 this->reserve(size_ + s.size_); 00103 memmove(p+size_, s.p, s.size_+1); // trailing 0 00104 size_ += s.size_; 00105 } 00106 return *this; 00107 } 00108 00109 // since p and s may overlap, we have to copy our own string first 00110 String& String::operator+=(const char* s) 00111 { 00112 const size_type lens = strlen(s); 00113 if (lens > 0) { 00114 if (size_ + lens + 1 <= allocated_) { 00115 memmove(p+size_, s, lens+1); // trailing 0 00116 size_ += lens; 00117 } else { 00118 String s2( *this ); // copy own data 00119 s2.reserve(size_ + lens); 00120 memmove(s2.p+size_, s, lens+1); // trailing 0 00121 s2.size_ = size_ + lens; 00122 this->swap( s2 ); 00123 } 00124 } 00125 return *this; 00126 } 00127 00128 String& String::operator+=(const char c) 00129 { 00130 push_back(c); 00131 return *this; 00132 } 00133 00134 void String::push_back(const char c) { 00135 00136 if (size_ == allocated_ - 1) { 00137 size_t more = (allocated_* 3) / 2; // factor 1.5 00138 if ( more < 4 ) more = 4; 00139 reserve( size_ + more ); 00140 } 00141 00142 p[size_] = c; 00143 size_++; 00144 p[size_] = 0; 00145 } 00146 00147 bool String::operator==(const char* s) const 00148 { 00149 if( s == NULL ) { 00150 if( p == NULL ) { 00151 return true; 00152 } 00153 return false; 00154 } 00155 bool ret = strcmp(p, s); 00156 return !ret; 00157 } 00158 00159 bool String::operator==(const String& s) const 00160 { 00161 bool ret = strcmp(p, s.p); 00162 return !ret; 00163 } 00164 00165 void String::clear() 00166 { 00167 size_ = 0; 00168 p[0] = 0; 00169 } 00170 00171 String String::substr(const size_type pos, size_type length) const 00172 { 00173 String s; 00174 const size_type len = size_; 00175 00176 if ( pos <= len ) { 00177 00178 size_type remain = len - pos; 00179 00180 if ( length > remain ) 00181 length = remain; 00182 00183 s.reserve( length ); 00184 00185 memcpy(s.p, p + pos, length); 00186 s.p[length] = '\0'; 00187 s.size_ = length; 00188 } 00189 return s; 00190 } 00191 00192 00193 // checked access, accessing the NUL at end is allowed 00194 char String::at(const size_type i) const 00195 { 00196 if ( i <= strlen(p) ) { 00197 return p[i]; 00198 } else { 00199 return '\0'; 00200 } 00201 } 00202 00203 String& String::erase(size_type pos, size_type len) 00204 { 00205 if (len > 0) { 00206 00207 if ( pos < size_ ) { // user must not remove trailing 0 00208 00209 size_type s2 = size_; 00210 size_type remain = s2 - pos - len; 00211 00212 if (remain > 0) { 00213 // erase by overwriting 00214 memmove(p + pos, p + pos + len, remain); 00215 } 00216 00217 //if ( remain < 0 ) remain = 0; 00218 00219 // remove unused space 00220 this->resize( pos+remain ); 00221 00222 } 00223 } 00224 return *this; 00225 } 00226 00227 String& String::append( const char* str, size_type n) { 00228 if (str && n > 0) { 00229 size_t lens = strlen(str); 00230 if (n > lens) 00231 n = lens; 00232 size_t newlen = size_ + n; 00233 this->reserve( newlen ); 00234 memmove(p+size_, str, n); // p and s.p MAY overlap 00235 p[newlen] = 0; // add NUL termination 00236 size_ = newlen; 00237 } 00238 return *this; 00239 } 00240 00241 String& String::append_raw( const char* str, size_type n) { 00242 if (str && n > 0) { 00243 size_t newlen = size_ + n; 00244 this->reserve( newlen ); 00245 memmove(p+size_, str, n); // p and s.p MAY overlap 00246 p[newlen] = 0; // add NUL termination 00247 size_ = newlen; 00248 } 00249 return *this; 00250 } 00251 00252 void String::append_int(int param) { 00253 00254 // max len of "-9223372036854775808" plus zero termination 00255 char conv_buff[20+1]; 00256 00257 int len = itoa_c(param, conv_buff); 00258 append_raw(conv_buff, len); 00259 } 00260 00261 int String::compare( size_type pos, size_type len, const String& str ) const { 00262 int r = -1; 00263 if (pos <= size_) { 00264 if ( len > size_ - pos) 00265 len = size_ - pos; // limit len to available length 00266 00267 const size_type osize = str.size(); 00268 const size_type len2 = MIN(len, osize); 00269 r = strncmp( p + pos, str.p, len2); 00270 if (r==0) // equal so far, now compare sizes 00271 r = len < osize ? -1 : ( len == osize ? 0 : +1 ); 00272 } 00273 return r; 00274 } 00275 00276 int String::compare( size_type pos, size_type len, const char* str ) const { 00277 int r = -1; 00278 if (pos <= size_) { 00279 00280 if ( len > size_ - pos) 00281 len = size_ - pos; // limit len to available length 00282 00283 const size_type osize = strlen(str); 00284 const size_type len2 = MIN(len, osize); 00285 r = strncmp( p + pos, str, len2); 00286 if (r==0) // equal so far, now compare sizes 00287 r = len < osize ? -1 : ( len == osize ? 0 : +1 ); 00288 } 00289 return r; 00290 } 00291 00292 int String::find_last_of(char c) const { 00293 int r = -1; 00294 char *v; 00295 v = strrchr(p,c); 00296 if (v != NULL) { 00297 r = 0; 00298 char* i = p; 00299 while (v != i) { 00300 i++; 00301 r++; 00302 } 00303 } 00304 return r; 00305 } 00306 00307 void String::new_realloc( size_type n) { 00308 if (n > 0 ) { 00309 char* pnew = static_cast<char*>(realloc(p, n)); // could return NULL 00310 if (pnew) 00311 p = pnew; 00312 } 00313 } 00314 00315 void String::reserve( const size_type n) { 00316 if (n >= allocated_ ) { 00317 this->new_realloc(n + 1); 00318 allocated_ = n + 1; 00319 } 00320 } 00321 00322 void String::resize( const size_type n) { 00323 this->resize( n, 0 ); 00324 } 00325 00326 void String::resize( const size_type n, const char c) { 00327 if (n < size_ ) { 00328 p[n] = 0; 00329 size_ = n; 00330 } 00331 else if (n > size_ ) { 00332 this->reserve( n ); 00333 for (size_type i=size_; i < n; ++i ) 00334 p[i] = c; 00335 p[n] = 0; 00336 size_ = n; 00337 } 00338 } 00339 00340 void String::swap(String& s) { 00341 00342 // do the swap manually, without relience on std::swap() as that is not always available 00343 size_t temp; 00344 char* tempPtr; 00345 00346 temp = allocated_; 00347 allocated_ = s.allocated_; 00348 s.allocated_ = temp; 00349 00350 temp = size_; 00351 size_ = s.size_; 00352 s.size_ = temp; 00353 00354 tempPtr = p; 00355 p = s.p; 00356 s.p = tempPtr; 00357 } 00358 00359 00360 // Comparison 00361 bool operator<( const String& s1, const String& s2 ) { 00362 return strcmp( s1.c_str(), s2.c_str() ) < 0; 00363 } 00364 00365 void reverse(char s[], uint32_t length) 00366 { 00367 uint32_t i, j; 00368 char c; 00369 00370 for (i = 0, j = length-1; i<j; i++, j--) { 00371 c = s[i]; 00372 s[i] = s[j]; 00373 s[j] = c; 00374 } 00375 } 00376 00377 uint32_t itoa_c (int64_t n, char s[]) 00378 { 00379 int64_t sign; 00380 uint32_t i; 00381 00382 if ((sign = n) < 0) 00383 n = -n; 00384 00385 i = 0; 00386 00387 do { 00388 s[i++] = n % 10 + '0'; 00389 } 00390 while ((n /= 10) > 0); 00391 00392 if (sign < 0) 00393 s[i++] = '-'; 00394 00395 s[i] = '\0'; 00396 00397 m2m::reverse(s, i); 00398 return i; 00399 } 00400 00401 uint8_t* String::convert_integer_to_array(int64_t value, uint8_t &size, const uint8_t *array, const uint32_t array_size) 00402 { 00403 uint8_t* buffer = NULL; 00404 size = 0; 00405 if (array) { 00406 value = String::convert_array_to_integer(array, array_size); 00407 } 00408 00409 if(value < 0xFF) { 00410 size = 1; 00411 } else if(value < 0xFFFF) { 00412 size = 2; 00413 } else if(value < 0xFFFFFF) { 00414 size = 3; 00415 } else if(value < 0xFFFFFFFF) { 00416 size = 4; 00417 } else if(value < 0xFFFFFFFFFF) { 00418 size = 5; 00419 } else if(value < 0xFFFFFFFFFFFF) { 00420 size = 6; 00421 } else if(value < 0xFFFFFFFFFFFFFF) { 00422 size = 7; 00423 } else { 00424 size = 8; 00425 } 00426 00427 buffer = (uint8_t*)malloc(size); 00428 if (buffer) { 00429 for (int i = 0; i < size; i++) { 00430 buffer[i] = (value >> ((size - i - 1) * 8)); 00431 } 00432 } else { 00433 size = 0; 00434 } 00435 return buffer; 00436 } 00437 00438 int64_t String::convert_array_to_integer(const uint8_t *value, const uint32_t size) 00439 { 00440 int64_t temp_64 = 0; 00441 for (int i = size - 1; i >= 0; i--) { 00442 temp_64 += (uint64_t)(*value++) << i * 8; 00443 } 00444 return temp_64; 00445 } 00446 00447 bool String::convert_ascii_to_int(const char *value, size_t length, int64_t &conversion_result) 00448 { 00449 unsigned int index = 0; 00450 00451 int64_t result = 0; 00452 00453 int sign; 00454 00455 int digit; 00456 00457 // return value, will be set to true if at least one digit is found 00458 // and a false is returned if 00459 // a) no digits found, ie. string is empty 00460 // b) a non-digit or non-'+' or non-'-' char is found. 00461 // c) more than one +, - chars are found 00462 // 00463 bool success = false; 00464 00465 // have predictable output value even on error 00466 conversion_result = 0; 00467 00468 // the optional sign needs to be the first char 00469 if ((length > 0) && (value[index] == '+')) { 00470 sign = 1; 00471 index++; 00472 } else if ((length > 0) && (value[index] == '-')) { 00473 sign = -1; 00474 index++; 00475 } else { 00476 sign = 1; 00477 } 00478 00479 while ((index < length) && (value[index] != 0)) { 00480 00481 const char c = value[index++]; 00482 00483 switch (c) { 00484 00485 case '0': 00486 case '1': 00487 case '2': 00488 case '3': 00489 case '4': 00490 case '5': 00491 case '6': 00492 case '7': 00493 case '8': 00494 case '9': 00495 digit = c - '0'; 00496 result *= 10; 00497 result += digit; 00498 success = true; // at least one digit was converted successfully 00499 break; 00500 00501 // there can be only one sign char and it must be the first 00502 case '+': 00503 case '-': 00504 default: 00505 // Note: the handling of having a number with digits in front and 00506 // non-digits at end (eg. "0zero") differs from sscanf() on glibc, 00507 // as sscanf will return what it got converted and a success value 00508 // even if the string ended with junk. 00509 conversion_result = 0; 00510 return false; 00511 } 00512 } 00513 00514 // put the sign in place 00515 result *= sign; 00516 00517 // and pass the result to caller 00518 conversion_result = result; 00519 00520 return success; 00521 } 00522 00523 } // namespace
Generated on Mon Aug 29 2022 19:53:40 by
