Mayank Gupta / Mbed OS pelion-example-frdm

Dependencies:   FXAS21002 FXOS8700Q

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers m2mstring.cpp Source File

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