LCOV - code coverage report
Current view: top level - u8stream/include/utf8stringbuf - utf8stringbuf.inl (source / functions) Hit Total Coverage
Test: crystal-facet-uml_v1.65.6_covts Lines: 143 143 100.0 %
Date: 2025-09-25 21:07:53 Functions: 22 22 100.0 %

          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             : #if __GNUC__ >= 8
     309             : #pragma GCC diagnostic push
     310             : #pragma GCC diagnostic ignored "-Wstringop-overflow"
     311             : #endif
     312       14052 :             memcpy( &((*this_).buf[start]), appendix, appLen+1 );
     313             : #if __GNUC__ >= 8
     314             : #pragma GCC diagnostic pop
     315             : #endif
     316             :         }
     317             :         else
     318             :         {
     319          14 :             const size_t appPartLen = ((*this_).size-start)-1;  /* cannot be negative */
     320          14 :             if (( appPartLen > 0 )&&( appPartLen <= PTRDIFF_MAX ))  /* check to suppress compiler warning */
     321             :             {
     322          13 :                 memcpy( &((*this_).buf[start]), appendix, appPartLen );
     323             :             }
     324             :             else
     325             :             {
     326             :                 /* buffer full */
     327             :             }
     328          14 :             utf8_string_buf_private_make_null_termination( this_ );
     329          14 :             result = UTF8ERROR_TRUNCATED;
     330             :         }
     331             : 
     332             :         /* For the standard use case, strlen and memcpy are faster than strncpy; strncat does not provide an error */
     333             :     }
     334       14067 :     return result;
     335             : }
     336             : 
     337           3 : static inline utf8error_t utf8stringbuf_append_buf( utf8stringbuf_t *this_, const utf8stringbuf_t *appendix ) {
     338           3 :     utf8error_t result = UTF8ERROR_SUCCESS;
     339           3 :     const size_t start = strlen( (*this_).buf );
     340             : 
     341           3 :     const size_t appLen = strlen( (*appendix).buf );
     342           3 :     if ( start + appLen < (*this_).size )
     343             :     {
     344           1 :         memcpy( &((*this_).buf[start]), (*appendix).buf, appLen+1 );
     345             :     }
     346             :     else
     347             :     {
     348           2 :         const size_t appPartLen = ((*this_).size-start)-1;
     349           2 :         if (( appPartLen > 0 )&&( appPartLen <= PTRDIFF_MAX ))  /* check to suppress compiler warning */
     350             :         {
     351           1 :             memcpy( &((*this_).buf[start]), (*appendix).buf, appPartLen );
     352             :         }
     353             :         else
     354             :         {
     355             :             /* buffer full */
     356             :         }
     357           2 :         utf8_string_buf_private_make_null_termination( this_ );
     358           2 :         result = UTF8ERROR_TRUNCATED;
     359             :     }
     360             : 
     361             :     /* For the standard use case, strlen and memcpy are faster than strncpy; strncat does not provide an error */
     362           3 :     return result;
     363             : }
     364             : 
     365        3416 : static inline utf8error_t utf8stringbuf_append_int( utf8stringbuf_t *this_, const int64_t appendix )
     366             : {
     367             :     char numberStr[21]; /* this is sufficient for signed 64 bit integers: -9223372036854775806 */
     368             :     /* Note: snprintf is not available on every OS */
     369        3416 :     sprintf( numberStr, utf8stringbuf_private_format_signed_64_bit_int, appendix );
     370        3416 :     return utf8stringbuf_append_str( this_, numberStr );
     371             : }
     372             : 
     373           3 : static inline utf8error_t utf8stringbuf_append_hex( utf8stringbuf_t *this_, const uint64_t appendix )
     374             : {
     375             :     char numberStr[17]; /* this is sufficient for 64 bit integers */
     376             :     /* Note: snprintf is not available on every OS */
     377           3 :     sprintf( numberStr, utf8stringbuf_private_format_64_bit_hex, appendix );
     378           3 :     return utf8stringbuf_append_str( this_, numberStr );
     379             : }
     380             : 
     381          61 : static inline utf8stringbuf_t utf8stringbuf_get_end( utf8stringbuf_t *this_ )
     382             : {
     383          61 :     unsigned int this_Length = utf8stringbuf_get_length( this_ );
     384          61 :     return utf8stringbuf_new( &((*this_).buf[this_Length]), (*this_).size - this_Length );
     385             : }
     386             : 
     387           9 : static inline utf8error_t utf8stringbuf_append_view( utf8stringbuf_t *this_, const utf8stringview_t *appendix )
     388             : {
     389           9 :     assert( appendix != NULL );
     390           9 :     utf8error_t result = UTF8ERROR_SUCCESS;
     391           9 :     const size_t start = strlen( (*this_).buf );
     392             : 
     393           9 :     const size_t appLen = utf8stringview_get_length( appendix );
     394           9 :     if ( start + appLen < (*this_).size )
     395             :     {
     396           7 :         memcpy( &((*this_).buf[start]), utf8stringview_get_start( appendix ), appLen );
     397           7 :         (*this_).buf[start+appLen] = '\0';
     398             :     }
     399             :     else
     400             :     {
     401           2 :         const size_t appPartLen = ((*this_).size-start)-1;
     402           2 :         if (( appPartLen > 0 )&&( appPartLen <= PTRDIFF_MAX ))  /* check to suppress compiler warning */
     403             :         {
     404           1 :             memcpy( &((*this_).buf[start]), utf8stringview_get_start( appendix ), appPartLen );
     405             :         }
     406             :         else
     407             :         {
     408             :             /* buffer full */
     409             :         }
     410           2 :         utf8_string_buf_private_make_null_termination( this_ );
     411           2 :         result = UTF8ERROR_TRUNCATED;
     412             :     }
     413             : 
     414           9 :     return result;
     415             : }
     416             : 
     417             : #ifdef __cplusplus
     418             : }
     419             : #endif
     420             : 
     421             : 
     422             : /*
     423             :  * Copyright 2012-2025 Andreas Warnke
     424             :  *
     425             :  * Licensed under the Apache License, Version 2.0 (the "License");
     426             :  * you may not use this file except in compliance with the License.
     427             :  * You may obtain a copy of the License at
     428             :  *
     429             :  *    http://www.apache.org/licenses/LICENSE-2.0
     430             :  *
     431             :  * Unless required by applicable law or agreed to in writing, software
     432             :  * distributed under the License is distributed on an "AS IS" BASIS,
     433             :  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     434             :  * See the License for the specific language governing permissions and
     435             :  * limitations under the License.
     436             :  */

Generated by: LCOV version 1.16