LCOV - code coverage report
Current view: top level - u8stream/include/utf8stringbuf - utf8stringbuf.inl (source / functions) Coverage Total Hit
Test: crystal-facet-uml_v1.66.0_covts Lines: 100.0 % 143 143
Test Date: 2025-10-11 12:10:40 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        42301 : static inline utf8stringbuf_t utf8stringbuf_new( char *buf, size_t size )
      72              : {
      73              :     utf8stringbuf_t result;
      74        42301 :     if (( buf == NULL )||(size==0))
      75              :     {
      76            1 :         result.size = 1;
      77            1 :         result.buf = utf8stringbuf_private_empty_buf;
      78              :     }
      79              :     else
      80              :     {
      81        42300 :         result.size = size;
      82        42300 :         result.buf = buf;
      83              :     }
      84        42301 :     return result;
      85              : }
      86              : 
      87         7778 : static inline void utf8stringbuf_clear( utf8stringbuf_t *this_ )
      88              : {
      89         7778 :     memset( (*this_).buf, '\0', (*this_).size );
      90         7778 : }
      91              : 
      92        20453 : static inline char* utf8stringbuf_get_string( const utf8stringbuf_t *this_ )
      93              : {
      94        20453 :     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         8298 : static inline unsigned int utf8stringbuf_get_length( const utf8stringbuf_t *this_ )
     103              : {
     104              :     unsigned int lenResult;
     105         8298 :     lenResult = strlen( (*this_).buf );
     106         8298 :     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              :     {
     124         5171 :         cmpResult = strcmp( (*this_).buf, that );
     125              :     }
     126         5173 :     return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE;
     127              : }
     128              : 
     129              : static inline int utf8stringbuf_equals_view( const utf8stringbuf_t *this_, const utf8stringview_t *that )
     130              : {
     131              :     assert( that != NULL );
     132              :     int result;
     133              :     const size_t len = utf8stringview_get_length( that );
     134              :     if ( len == utf8stringbuf_get_length(this_) )
     135              :     {
     136              :         if ( ( len == 0 )/*&&( (*this_).length == 0 )*/)
     137              :         {
     138              :             result = 1;
     139              :         }
     140              :         else
     141              :         {
     142              :             result = ( 0 == memcmp ( (*this_).buf, utf8stringview_get_start(that), len ) ) ? 1 : 0;
     143              :         }
     144              :     }
     145              :     else
     146              :     {
     147              :         result = 0;
     148              :     }
     149              :     return result;
     150              : }
     151              : 
     152            4 : static inline int utf8stringbuf_equals_buf( const utf8stringbuf_t *this_, const utf8stringbuf_t *that )
     153              : {
     154            4 :     int cmpResult = -1;
     155            4 :     cmpResult = strcmp( (*this_).buf, (*that).buf );
     156            4 :     return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE;
     157              : }
     158              : 
     159              : static inline int utf8stringbuf_find_first_buf( const utf8stringbuf_t *this_, const utf8stringbuf_t pattern )
     160              : {
     161              :     int result = UTF8STRINGBUF_NOT_FOUND;
     162              :     const char *ptrResult = strstr( (*this_).buf, pattern.buf );
     163              :     if ( ptrResult != NULL )
     164              :     {
     165              :         result = (int) (ptrResult - (*this_).buf);
     166              :     }
     167              :     return result;
     168              : }
     169              : 
     170            6 : static inline int utf8stringbuf_starts_with_str( const utf8stringbuf_t *this_, const char *that )
     171              : {
     172            6 :     int cmpResult = -1;
     173            6 :     if ( that != NULL )
     174              :     {
     175            5 :         unsigned int thatLen = strlen( that );
     176            5 :         cmpResult = strncmp( (*this_).buf, that, thatLen );
     177              :     }
     178            6 :     return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE;
     179              : }
     180              : 
     181            5 : static inline int utf8stringbuf_starts_with_buf( const utf8stringbuf_t *this_, const utf8stringbuf_t *that )
     182              : {
     183            5 :     int cmpResult = -1;
     184            5 :     unsigned int thatLen = strlen( (*that).buf );
     185            5 :     cmpResult = strncmp( (*this_).buf, (*that).buf, thatLen );
     186            5 :     return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE;
     187              : }
     188              : 
     189            6 : static inline int utf8stringbuf_ends_with_str( const utf8stringbuf_t *this_, const char *that )
     190              : {
     191            6 :     int cmpResult = -1;
     192            6 :     if ( that != NULL )
     193              :     {
     194            5 :         unsigned int thatLen = strlen( that );
     195            5 :         unsigned int thisLen = strlen( (*this_).buf );
     196            5 :         if ( thatLen <= thisLen )
     197              :         {
     198            4 :             cmpResult = memcmp( &((*this_).buf[thisLen-thatLen]), that, thatLen );
     199              :         }
     200              :     }
     201            6 :     return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE;
     202              : }
     203              : 
     204            5 : static inline int utf8stringbuf_ends_with_buf( const utf8stringbuf_t *this_, const utf8stringbuf_t *that )
     205              : {
     206            5 :     int cmpResult = -1;
     207            5 :     unsigned int thatLen = strlen( (*that).buf );
     208            5 :     unsigned int thisLen = strlen( (*this_).buf );
     209            5 :     if ( thatLen <= thisLen )
     210              :     {
     211            4 :         cmpResult = memcmp( &((*this_).buf[thisLen-thatLen]), (*that).buf, thatLen );
     212              :     }
     213            5 :     return ( cmpResult == 0 ) ? UTF8STRINGBUF_TRUE : UTF8STRINGBUF_FALSE;
     214              : }
     215              : 
     216            4 : static inline utf8error_t utf8stringbuf_copy_buf( utf8stringbuf_t *this_, const utf8stringbuf_t *original )
     217              : {
     218            4 :     utf8error_t complete = UTF8ERROR_SUCCESS;
     219              : #if __GNUC__ >= 8
     220              : #pragma GCC diagnostic push
     221              : #pragma GCC diagnostic ignored "-Wstringop-truncation"
     222              : #endif
     223            4 :     strncpy( (*this_).buf, (*original).buf, (*this_).size );
     224              : #if __GNUC__ >= 8
     225              : #pragma GCC diagnostic pop
     226              : #endif
     227            4 :     if ( (*this_).buf[(*this_).size-1] != '\0' )
     228              :     {
     229            2 :         utf8_string_buf_private_make_null_termination( this_ );
     230            2 :         complete = UTF8ERROR_TRUNCATED;
     231              :     }
     232            4 :     return complete;
     233              : }
     234              : 
     235        34250 : static inline utf8error_t utf8stringbuf_copy_str( utf8stringbuf_t *this_, const char *original )
     236              : {
     237        34250 :     utf8error_t complete = UTF8ERROR_SUCCESS;
     238        34250 :     if ( original == NULL )
     239              :     {
     240            1 :         (*this_).buf[0] = '\0';
     241            1 :         complete = UTF8ERROR_NULL_PARAM;
     242              :     }
     243              :     else
     244              :     {
     245              : #if __GNUC__ >= 8
     246              : #pragma GCC diagnostic push
     247              : #pragma GCC diagnostic ignored "-Wstringop-truncation"
     248              : #endif
     249        34249 :         strncpy( (*this_).buf, original, (*this_).size );
     250              : #if __GNUC__ >= 8
     251              : #pragma GCC diagnostic pop
     252              : #endif
     253        34249 :         if ( (*this_).buf[(*this_).size-1] != '\0' )
     254              :         {
     255           63 :             utf8_string_buf_private_make_null_termination( this_ );
     256           63 :             complete = UTF8ERROR_TRUNCATED;
     257              :         }
     258              :     }
     259        34250 :     return complete;
     260              : }
     261              : 
     262           38 : static inline utf8error_t utf8stringbuf_copy_view( utf8stringbuf_t *this_, const utf8stringview_t *original )
     263              : {
     264           38 :     assert( original != NULL );
     265           38 :     utf8error_t result = UTF8ERROR_SUCCESS;
     266              : 
     267           38 :     const size_t origLen = utf8stringview_get_length( original );
     268           38 :     if ( origLen < (*this_).size )
     269              :     {
     270           36 :         memcpy( &((*this_).buf[0]), utf8stringview_get_start( original ), origLen );
     271           36 :         (*this_).buf[origLen] = '\0';
     272              :     }
     273              :     else
     274              :     {
     275            2 :         if ( (*this_).size > 0 )
     276              :         {
     277            2 :             memcpy( &((*this_).buf[0]), utf8stringview_get_start( original ), ((*this_).size-1) );
     278              :         }
     279              :         else
     280              :         {
     281              :             /* buffer non-existant */
     282              :         }
     283            2 :         utf8_string_buf_private_make_null_termination( this_ );
     284            2 :         result = UTF8ERROR_TRUNCATED;
     285              :     }
     286              : 
     287           38 :     return result;
     288              : }
     289              : 
     290        14067 : static inline utf8error_t utf8stringbuf_append_str( utf8stringbuf_t *this_, const char *appendix )
     291              : {
     292        14067 :     utf8error_t result = UTF8ERROR_SUCCESS;
     293        14067 :     if ( appendix == NULL )
     294              :     {
     295            1 :         result = UTF8ERROR_NULL_PARAM;
     296              :     }
     297              :     else
     298              :     {
     299        14066 :         const size_t start = strlen( (*this_).buf );
     300              : 
     301        14066 :         const size_t appLen = strlen( appendix );
     302        14066 :         if ( ( start + appLen ) < (*this_).size )
     303              :         {
     304              :             /* gcc may not reliably evaluate the if condition above */
     305              :             /* possibly related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105329 */
     306              :             /* or https://gcc.gnu.org/bugzilla/show_bug.cgi?id=89689 */
     307        14052 :             assert( ( start + appLen + 1 ) <= (*this_).size );
     308        14052 :             memcpy( &((*this_).buf[start]), appendix, appLen+1 );
     309              :         }
     310              :         else
     311              :         {
     312           14 :             const size_t appPartLen = ((*this_).size-start)-1;  /* cannot be negative */
     313           14 :             if (( appPartLen > 0 )&&( appPartLen <= PTRDIFF_MAX ))  /* check to suppress compiler warning */
     314              :             {
     315           13 :                 memcpy( &((*this_).buf[start]), appendix, appPartLen );
     316              :             }
     317              :             else
     318              :             {
     319              :                 /* buffer full */
     320              :             }
     321           14 :             utf8_string_buf_private_make_null_termination( this_ );
     322           14 :             result = UTF8ERROR_TRUNCATED;
     323              :         }
     324              : 
     325              :         /* For the standard use case, strlen and memcpy are faster than strncpy; strncat does not provide an error */
     326              :     }
     327        14067 :     return result;
     328              : }
     329              : 
     330            3 : static inline utf8error_t utf8stringbuf_append_buf( utf8stringbuf_t *this_, const utf8stringbuf_t *appendix ) {
     331            3 :     utf8error_t result = UTF8ERROR_SUCCESS;
     332            3 :     const size_t start = strlen( (*this_).buf );
     333              : 
     334            3 :     const size_t appLen = strlen( (*appendix).buf );
     335            3 :     if ( start + appLen < (*this_).size )
     336              :     {
     337            1 :         memcpy( &((*this_).buf[start]), (*appendix).buf, appLen+1 );
     338              :     }
     339              :     else
     340              :     {
     341            2 :         const size_t appPartLen = ((*this_).size-start)-1;
     342            2 :         if (( appPartLen > 0 )&&( appPartLen <= PTRDIFF_MAX ))  /* check to suppress compiler warning */
     343              :         {
     344            1 :             memcpy( &((*this_).buf[start]), (*appendix).buf, appPartLen );
     345              :         }
     346              :         else
     347              :         {
     348              :             /* buffer full */
     349              :         }
     350            2 :         utf8_string_buf_private_make_null_termination( this_ );
     351            2 :         result = UTF8ERROR_TRUNCATED;
     352              :     }
     353              : 
     354              :     /* For the standard use case, strlen and memcpy are faster than strncpy; strncat does not provide an error */
     355            3 :     return result;
     356              : }
     357              : 
     358         3416 : static inline utf8error_t utf8stringbuf_append_int( utf8stringbuf_t *this_, const int64_t appendix )
     359              : {
     360              :     char numberStr[21]; /* this is sufficient for signed 64 bit integers: -9223372036854775806 */
     361              :     /* Note: snprintf is not available on every OS */
     362         3416 :     sprintf( numberStr, utf8stringbuf_private_format_signed_64_bit_int, appendix );
     363         3416 :     return utf8stringbuf_append_str( this_, numberStr );
     364              : }
     365              : 
     366            3 : static inline utf8error_t utf8stringbuf_append_hex( utf8stringbuf_t *this_, const uint64_t appendix )
     367              : {
     368              :     char numberStr[17]; /* this is sufficient for 64 bit integers */
     369              :     /* Note: snprintf is not available on every OS */
     370            3 :     sprintf( numberStr, utf8stringbuf_private_format_64_bit_hex, appendix );
     371            3 :     return utf8stringbuf_append_str( this_, numberStr );
     372              : }
     373              : 
     374           61 : static inline utf8stringbuf_t utf8stringbuf_get_end( utf8stringbuf_t *this_ )
     375              : {
     376           61 :     unsigned int this_Length = utf8stringbuf_get_length( this_ );
     377           61 :     return utf8stringbuf_new( &((*this_).buf[this_Length]), (*this_).size - this_Length );
     378              : }
     379              : 
     380            9 : static inline utf8error_t utf8stringbuf_append_view( utf8stringbuf_t *this_, const utf8stringview_t *appendix )
     381              : {
     382            9 :     assert( appendix != NULL );
     383            9 :     utf8error_t result = UTF8ERROR_SUCCESS;
     384            9 :     const size_t start = strlen( (*this_).buf );
     385              : 
     386            9 :     const size_t appLen = utf8stringview_get_length( appendix );
     387            9 :     if ( start + appLen < (*this_).size )
     388              :     {
     389            7 :         memcpy( &((*this_).buf[start]), utf8stringview_get_start( appendix ), appLen );
     390            7 :         (*this_).buf[start+appLen] = '\0';
     391              :     }
     392              :     else
     393              :     {
     394            2 :         const size_t appPartLen = ((*this_).size-start)-1;
     395            2 :         if (( appPartLen > 0 )&&( appPartLen <= PTRDIFF_MAX ))  /* check to suppress compiler warning */
     396              :         {
     397            1 :             memcpy( &((*this_).buf[start]), utf8stringview_get_start( appendix ), appPartLen );
     398              :         }
     399              :         else
     400              :         {
     401              :             /* buffer full */
     402              :         }
     403            2 :         utf8_string_buf_private_make_null_termination( this_ );
     404            2 :         result = UTF8ERROR_TRUNCATED;
     405              :     }
     406              : 
     407            9 :     return result;
     408              : }
     409              : 
     410              : #ifdef __cplusplus
     411              : }
     412              : #endif
     413              : 
     414              : 
     415              : /*
     416              :  * Copyright 2012-2025 Andreas Warnke
     417              :  *
     418              :  * Licensed under the Apache License, Version 2.0 (the "License");
     419              :  * you may not use this file except in compliance with the License.
     420              :  * You may obtain a copy of the License at
     421              :  *
     422              :  *    http://www.apache.org/licenses/LICENSE-2.0
     423              :  *
     424              :  * Unless required by applicable law or agreed to in writing, software
     425              :  * distributed under the License is distributed on an "AS IS" BASIS,
     426              :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     427              :  * See the License for the specific language governing permissions and
     428              :  * limitations under the License.
     429              :  */
        

Generated by: LCOV version 2.0-1