LCOV - code coverage report
Current view: top level - u8stream/include/utf8stringbuf - utf8stringbuf.inl (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.63.2_covts Lines: 100.0 % 142 142
Test Date: 2025-05-01 10:10:14 Functions: 100.0 % 22 22

            Line data    Source code
       1              : /* File: utf8stringbuf.inl; Copyright and License: see below */
       2              : 
       3              : #include "utf8stringbuf/utf8codepoint.h"
       4              : #include <string.h>
       5              : #include <stdio.h>
       6              : #include <stdint.h>
       7              : 
       8              : #ifdef __cplusplus
       9              : extern "C" {
      10              : #endif
      11              : 
      12              : /*!
      13              :  *  \enum utf8stringbuf_bool_enum
      14              :  *  \private
      15              :  */
      16              : /*  enumeration for true and false or success and failure */
      17              : enum utf8stringbuf_bool_enum {UTF8STRINGBUF_FALSE=0, UTF8STRINGBUF_TRUE=1,};
      18              : 
      19              : /*!
      20              :  *  \enum utf8stringbuf_search_enum
      21              :  *  \private
      22              :  */
      23              : /*  enumeration for search pattern not found */
      24              : enum utf8stringbuf_search_enum {UTF8STRINGBUF_NOT_FOUND=-1,};
      25              : 
      26              : /*!
      27              :  *  \var utf8stringbuf_private_format_signed_64_bit_int
      28              :  *  \private
      29              :  */
      30              : /*  a character array containing nothing but a single zero */
      31              : extern const char *utf8stringbuf_private_format_signed_64_bit_int;
      32              : 
      33              : /*!
      34              :  *  \var utf8stringbuf_private_format_64_bit_hex
      35              :  *  \private
      36              :  */
      37              : /*  a character array containing nothing but a single zero */
      38              : extern const char *utf8stringbuf_private_format_64_bit_hex;
      39              : 
      40              : /*!
      41              :  *  \var utf8stringbuf_private_empty_buf
      42              :  *  \private
      43              :  */
      44              : /*  a character array containing nothing but a single zero */
      45              : extern char utf8stringbuf_private_empty_buf[1];
      46              : 
      47              : /*!
      48              :  *  \fn utf8_string_buf_private_make_null_termination( utf8stringbuf_t *this_ )
      49              :  *  \private
      50              :  *  \return new, truncated length of the string
      51              :  */
      52              : /* function to make a buffer null terminated while ensuring that all utf8 character sequences are valid */
      53              : extern unsigned int utf8_string_buf_private_make_null_termination( utf8stringbuf_t *this_ );
      54              : 
      55           15 : static inline utf8stringbuf_t utf8stringbuf( char *that )
      56              : {
      57              :     utf8stringbuf_t result;
      58           15 :     if ( that == NULL )
      59              :     {
      60            1 :         result.size = 1;
      61            1 :         result.buf = utf8stringbuf_private_empty_buf;
      62              :     }
      63              :     else
      64              :     {
      65           14 :         result.size = strlen( that )+1;
      66           14 :         result.buf = that;
      67              :     }
      68           15 :     return result;
      69              : }
      70              : 
      71        42247 : static inline utf8stringbuf_t utf8stringbuf_new( char *buf, size_t size )
      72              : {
      73              :     utf8stringbuf_t result;
      74        42247 :     if (( buf == NULL )||(size==0))
      75              :     {
      76            1 :         result.size = 1;
      77            1 :         result.buf = utf8stringbuf_private_empty_buf;
      78              :     }
      79              :     else
      80              :     {
      81        42246 :         result.size = size;
      82        42246 :         result.buf = buf;
      83              :     }
      84        42247 :     return result;
      85              : }
      86              : 
      87         7764 : static inline void utf8stringbuf_clear( utf8stringbuf_t *this_ )
      88              : {
      89         7764 :     memset( (*this_).buf, '\0', (*this_).size );
      90         7764 : }
      91              : 
      92        20353 : static inline char* utf8stringbuf_get_string( const utf8stringbuf_t *this_ )
      93              : {
      94        20353 :     return (*this_).buf;
      95              : }
      96              : 
      97         1174 : static inline size_t utf8stringbuf_get_size( const utf8stringbuf_t *this_ )
      98              : {
      99         1174 :     return (*this_).size;
     100              : }
     101              : 
     102         8288 : static inline unsigned int utf8stringbuf_get_length( const utf8stringbuf_t *this_ )
     103              : {
     104              :     unsigned int lenResult;
     105         8288 :     lenResult = strlen( (*this_).buf );
     106         8288 :     return lenResult;
     107              : }
     108              : 
     109            1 : static inline utf8stringview_t utf8stringbuf_get_view( const utf8stringbuf_t *this_ )
     110              : {
     111              :     utf8stringview_t result;
     112            1 :     assert( NULL != (*this_).buf );
     113            1 :     const utf8error_t err = utf8stringview_init( &result, (*this_).buf, strlen( (*this_).buf ) );
     114            1 :     assert( UTF8ERROR_SUCCESS == err );
     115              :     (void) err;  /* do not warn on unused value */
     116            1 :     return result;
     117              : }
     118              : 
     119         5173 : static inline int utf8stringbuf_equals_str( const utf8stringbuf_t *this_, const char *that )
     120              : {
     121         5173 :     int cmpResult = -1;
     122         5173 :     if ( that != NULL ) {
     123         5171 :         cmpResult = strcmp( (*this_).buf, that );
     124              :     }
     125         5173 :     return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE;
     126              : }
     127              : 
     128              : static inline int utf8stringbuf_equals_view( const utf8stringbuf_t *this_, const utf8stringview_t *that )
     129              : {
     130              :     assert( that != NULL );
     131              :     int result;
     132              :     const size_t len = utf8stringview_get_length( that );
     133              :     if ( len == utf8stringbuf_get_length(this_) )
     134              :     {
     135              :         if ( ( len == 0 )/*&&( (*this_).length == 0 )*/)
     136              :         {
     137              :             result = 1;
     138              :         }
     139              :         else
     140              :         {
     141              :             result = ( 0 == memcmp ( (*this_).buf, utf8stringview_get_start(that), len ) ) ? 1 : 0;
     142              :         }
     143              :     }
     144              :     else
     145              :     {
     146              :         result = 0;
     147              :     }
     148              :     return result;
     149              : }
     150              : 
     151            4 : static inline int utf8stringbuf_equals_buf( const utf8stringbuf_t *this_, const utf8stringbuf_t *that )
     152              : {
     153            4 :     int cmpResult = -1;
     154            4 :     cmpResult = strcmp( (*this_).buf, (*that).buf );
     155            4 :     return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE;
     156              : }
     157              : 
     158              : static inline int utf8stringbuf_find_first_buf( const utf8stringbuf_t *this_, const utf8stringbuf_t pattern )
     159              : {
     160              :     int result = UTF8STRINGBUF_NOT_FOUND;
     161              :     const char *ptrResult = strstr( (*this_).buf, pattern.buf );
     162              :     if ( ptrResult != NULL ) {
     163              :         result = (int) (ptrResult - (*this_).buf);
     164              :     }
     165              :     return result;
     166              : }
     167              : 
     168            6 : static inline int utf8stringbuf_starts_with_str( const utf8stringbuf_t *this_, const char *that )
     169              : {
     170            6 :     int cmpResult = -1;
     171            6 :     if ( that != NULL ) {
     172            5 :         unsigned int thatLen = strlen( that );
     173            5 :         cmpResult = strncmp( (*this_).buf, that, thatLen );
     174              :     }
     175            6 :     return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE;
     176              : }
     177              : 
     178            5 : static inline int utf8stringbuf_starts_with_buf( const utf8stringbuf_t *this_, const utf8stringbuf_t *that ) {
     179            5 :     int cmpResult = -1;
     180            5 :     unsigned int thatLen = strlen( (*that).buf );
     181            5 :     cmpResult = strncmp( (*this_).buf, (*that).buf, thatLen );
     182            5 :     return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE;
     183              : }
     184              : 
     185            6 : static inline int utf8stringbuf_ends_with_str( const utf8stringbuf_t *this_, const char *that ) {
     186            6 :     int cmpResult = -1;
     187            6 :     if ( that != NULL ) {
     188            5 :         unsigned int thatLen = strlen( that );
     189            5 :         unsigned int thisLen = strlen( (*this_).buf );
     190            5 :         if ( thatLen <= thisLen ) {
     191            4 :             cmpResult = memcmp( &((*this_).buf[thisLen-thatLen]), that, thatLen );
     192              :         }
     193              :     }
     194            6 :     return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE;
     195              : }
     196              : 
     197            5 : static inline int utf8stringbuf_ends_with_buf( const utf8stringbuf_t *this_, const utf8stringbuf_t *that ) {
     198            5 :     int cmpResult = -1;
     199            5 :     unsigned int thatLen = strlen( (*that).buf );
     200            5 :     unsigned int thisLen = strlen( (*this_).buf );
     201            5 :     if ( thatLen <= thisLen ) {
     202            4 :         cmpResult = memcmp( &((*this_).buf[thisLen-thatLen]), (*that).buf, thatLen );
     203              :     }
     204            5 :     return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE;
     205              : }
     206              : 
     207            4 : static inline utf8error_t utf8stringbuf_copy_buf( utf8stringbuf_t *this_, const utf8stringbuf_t *original ) {
     208            4 :     utf8error_t complete = UTF8ERROR_SUCCESS;
     209              : #if __GNUC__ >= 8
     210              : #pragma GCC diagnostic push
     211              : #pragma GCC diagnostic ignored "-Wstringop-truncation"
     212              : #endif
     213            4 :     strncpy( (*this_).buf, (*original).buf, (*this_).size );
     214              : #if __GNUC__ >= 8
     215              : #pragma GCC diagnostic pop
     216              : #endif
     217            4 :     if ( (*this_).buf[(*this_).size-1] != '\0' ) {
     218            2 :         utf8_string_buf_private_make_null_termination( this_ );
     219            2 :         complete = UTF8ERROR_TRUNCATED;
     220              :     }
     221            4 :     return complete;
     222              : }
     223              : 
     224        34158 : static inline utf8error_t utf8stringbuf_copy_str( utf8stringbuf_t *this_, const char *original ) {
     225        34158 :     utf8error_t complete = UTF8ERROR_SUCCESS;
     226        34158 :     if ( original == NULL ) {
     227            1 :         (*this_).buf[0] = '\0';
     228            1 :         complete = UTF8ERROR_NULL_PARAM;
     229              :     }
     230              :     else {
     231              : #if __GNUC__ >= 8
     232              : #pragma GCC diagnostic push
     233              : #pragma GCC diagnostic ignored "-Wstringop-truncation"
     234              : #endif
     235        34157 :         strncpy( (*this_).buf, original, (*this_).size );
     236              : #if __GNUC__ >= 8
     237              : #pragma GCC diagnostic pop
     238              : #endif
     239        34157 :         if ( (*this_).buf[(*this_).size-1] != '\0' ) {
     240           63 :             utf8_string_buf_private_make_null_termination( this_ );
     241           63 :             complete = UTF8ERROR_TRUNCATED;
     242              :         }
     243              :     }
     244        34158 :     return complete;
     245              : }
     246              : 
     247           38 : static inline utf8error_t utf8stringbuf_copy_view( utf8stringbuf_t *this_, const utf8stringview_t *original )
     248              : {
     249           38 :     assert( original != NULL );
     250           38 :     utf8error_t result = UTF8ERROR_SUCCESS;
     251              : 
     252           38 :     const size_t origLen = utf8stringview_get_length( original );
     253           38 :     if ( origLen < (*this_).size ) {
     254           36 :         memcpy( &((*this_).buf[0]), utf8stringview_get_start( original ), origLen );
     255           36 :         (*this_).buf[origLen] = '\0';
     256              :     }
     257              :     else {
     258            2 :         if ( (*this_).size > 0 )
     259              :         {
     260            2 :             memcpy( &((*this_).buf[0]), utf8stringview_get_start( original ), ((*this_).size-1) );
     261              :         }
     262              :         else
     263              :         {
     264              :             /* buffer non-existant */
     265              :         }
     266            2 :         utf8_string_buf_private_make_null_termination( this_ );
     267            2 :         result = UTF8ERROR_TRUNCATED;
     268              :     }
     269              : 
     270           38 :     return result;
     271              : }
     272              : 
     273        13951 : static inline utf8error_t utf8stringbuf_append_str( utf8stringbuf_t *this_, const char *appendix ) {
     274        13951 :     utf8error_t result = UTF8ERROR_SUCCESS;
     275        13951 :     if ( appendix == NULL ) {
     276            1 :         result = UTF8ERROR_NULL_PARAM;
     277              :     }
     278              :     else {
     279        13950 :         const size_t start = strlen( (*this_).buf );
     280              : 
     281        13950 :         const size_t appLen = strlen( appendix );
     282        13950 :         if ( start + appLen < (*this_).size ) {
     283              :             /* gcc does not reliably evaluate the if condition above */
     284              : #if __GNUC__ >= 8
     285              : #pragma GCC diagnostic push
     286              : #pragma GCC diagnostic ignored "-Wstringop-overflow"
     287              : #endif
     288        13936 :             memcpy( &((*this_).buf[start]), appendix, appLen+1 );
     289              : #if __GNUC__ >= 8
     290              : #pragma GCC diagnostic pop
     291              : #endif
     292              :         }
     293              :         else {
     294           14 :             const size_t appPartLen = ((*this_).size-start)-1;  /* cannot be negative */
     295           14 :             if (( appPartLen > 0 )&&( appPartLen <= PTRDIFF_MAX ))  /* check to suppress compiler warning */
     296              :             {
     297           13 :                 memcpy( &((*this_).buf[start]), appendix, appPartLen );
     298              :             }
     299              :             else
     300              :             {
     301              :                 /* buffer full */
     302              :             }
     303           14 :             utf8_string_buf_private_make_null_termination( this_ );
     304           14 :             result = UTF8ERROR_TRUNCATED;
     305              :         }
     306              : 
     307              :         /* For the standard use case, strlen and memcpy are faster than strncpy; strncat does not provide an error */
     308              :     }
     309        13951 :     return result;
     310              : }
     311              : 
     312            3 : static inline utf8error_t utf8stringbuf_append_buf( utf8stringbuf_t *this_, const utf8stringbuf_t *appendix ) {
     313            3 :     utf8error_t result = UTF8ERROR_SUCCESS;
     314            3 :     const size_t start = strlen( (*this_).buf );
     315              : 
     316            3 :     const size_t appLen = strlen( (*appendix).buf );
     317            3 :     if ( start + appLen < (*this_).size ) {
     318            1 :         memcpy( &((*this_).buf[start]), (*appendix).buf, appLen+1 );
     319              :     }
     320              :     else {
     321            2 :         const size_t appPartLen = ((*this_).size-start)-1;
     322            2 :         if (( appPartLen > 0 )&&( appPartLen <= PTRDIFF_MAX ))  /* check to suppress compiler warning */
     323              :         {
     324            1 :             memcpy( &((*this_).buf[start]), (*appendix).buf, appPartLen );
     325              :         }
     326              :         else
     327              :         {
     328              :             /* buffer full */
     329              :         }
     330            2 :         utf8_string_buf_private_make_null_termination( this_ );
     331            2 :         result = UTF8ERROR_TRUNCATED;
     332              :     }
     333              : 
     334              :     /* For the standard use case, strlen and memcpy are faster than strncpy; strncat does not provide an error */
     335            3 :     return result;
     336              : }
     337              : 
     338         3383 : static inline utf8error_t utf8stringbuf_append_int( utf8stringbuf_t *this_, const int64_t appendix ) {
     339              :     char numberStr[21]; /* this is sufficient for signed 64 bit integers: -9223372036854775806 */
     340              :     /* Note: snprintf is not available on every OS */
     341         3383 :     sprintf( numberStr, utf8stringbuf_private_format_signed_64_bit_int, appendix );
     342         3383 :     return utf8stringbuf_append_str( this_, numberStr );
     343              : }
     344              : 
     345            3 : static inline utf8error_t utf8stringbuf_append_hex( utf8stringbuf_t *this_, const uint64_t appendix ) {
     346              :     char numberStr[17]; /* this is sufficient for 64 bit integers */
     347              :     /* Note: snprintf is not available on every OS */
     348            3 :     sprintf( numberStr, utf8stringbuf_private_format_64_bit_hex, appendix );
     349            3 :     return utf8stringbuf_append_str( this_, numberStr );
     350              : }
     351              : 
     352           61 : static inline utf8stringbuf_t utf8stringbuf_get_end( utf8stringbuf_t *this_ ) {
     353           61 :     unsigned int this_Length = utf8stringbuf_get_length( this_ );
     354           61 :     return utf8stringbuf_new( &((*this_).buf[this_Length]), (*this_).size - this_Length );
     355              : }
     356              : 
     357            9 : static inline utf8error_t utf8stringbuf_append_view( utf8stringbuf_t *this_, const utf8stringview_t *appendix )
     358              : {
     359            9 :     assert( appendix != NULL );
     360            9 :     utf8error_t result = UTF8ERROR_SUCCESS;
     361            9 :     const size_t start = strlen( (*this_).buf );
     362              : 
     363            9 :     const size_t appLen = utf8stringview_get_length( appendix );
     364            9 :     if ( start + appLen < (*this_).size ) {
     365            7 :         memcpy( &((*this_).buf[start]), utf8stringview_get_start( appendix ), appLen );
     366            7 :         (*this_).buf[start+appLen] = '\0';
     367              :     }
     368              :     else {
     369            2 :         const size_t appPartLen = ((*this_).size-start)-1;
     370            2 :         if (( appPartLen > 0 )&&( appPartLen <= PTRDIFF_MAX ))  /* check to suppress compiler warning */
     371              :         {
     372            1 :             memcpy( &((*this_).buf[start]), utf8stringview_get_start( appendix ), appPartLen );
     373              :         }
     374              :         else
     375              :         {
     376              :             /* buffer full */
     377              :         }
     378            2 :         utf8_string_buf_private_make_null_termination( this_ );
     379            2 :         result = UTF8ERROR_TRUNCATED;
     380              :     }
     381              : 
     382            9 :     return result;
     383              : }
     384              : 
     385              : #ifdef __cplusplus
     386              : }
     387              : #endif
     388              : 
     389              : 
     390              : /*
     391              :  * Copyright 2012-2025 Andreas Warnke
     392              :  *
     393              :  * Licensed under the Apache License, Version 2.0 (the "License");
     394              :  * you may not use this file except in compliance with the License.
     395              :  * You may obtain a copy of the License at
     396              :  *
     397              :  *    http://www.apache.org/licenses/LICENSE-2.0
     398              :  *
     399              :  * Unless required by applicable law or agreed to in writing, software
     400              :  * distributed under the License is distributed on an "AS IS" BASIS,
     401              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     402              :  * See the License for the specific language governing permissions and
     403              :  * limitations under the License.
     404              :  */
        

Generated by: LCOV version 2.0-1