LCOV - code coverage report
Current view: top level - src/support - utf8.c (source / functions) Hit Total Coverage
Test: [build process] commit ef510b1f346f4c9f9d86eaceace5ca54961a1dbc Lines: 126 332 38.0 %
Date: 2022-07-17 01:01:28 Functions: 10 24 41.7 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 87 280 31.1 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :   Basic UTF-8 manipulation routines
       3                 :            :   by Jeff Bezanson
       4                 :            :   placed in the public domain Fall 2005
       5                 :            : 
       6                 :            :   This code is designed to provide the utilities you need to manipulate
       7                 :            :   UTF-8 as an internal string encoding. These functions do not perform the
       8                 :            :   error checking normally needed when handling UTF-8 data, so if you happen
       9                 :            :   to be from the Unicode Consortium you will want to flay me alive.
      10                 :            :   I do this because error checking can be performed at the boundaries (I/O),
      11                 :            :   with these routines reserved for higher performance on data known to be
      12                 :            :   valid.
      13                 :            :   A UTF-8 validation routine is included.
      14                 :            : */
      15                 :            : #include <stdlib.h>
      16                 :            : #include <stdio.h>
      17                 :            : #include <string.h>
      18                 :            : #include <stdarg.h>
      19                 :            : #include <stdint.h>
      20                 :            : #include <wchar.h>
      21                 :            : #include <wctype.h>
      22                 :            : 
      23                 :            : #include "utf8proc.h"
      24                 :            : #undef JL_DLLEXPORT /* avoid conflicting definition */
      25                 :            : 
      26                 :            : #include "dtypes.h"
      27                 :            : 
      28                 :            : #ifdef _OS_WINDOWS_
      29                 :            : #include <malloc.h>
      30                 :            : #define snprintf _snprintf
      31                 :            : #else
      32                 :            : #ifndef __FreeBSD__
      33                 :            : #include <alloca.h>
      34                 :            : #endif /* __FreeBSD__ */
      35                 :            : #endif
      36                 :            : #include <assert.h>
      37                 :            : 
      38                 :            : #include "utf8.h"
      39                 :            : 
      40                 :            : #ifdef __cplusplus
      41                 :            : extern "C" {
      42                 :            : #endif
      43                 :            : 
      44                 :            : static const uint32_t offsetsFromUTF8[6] = {
      45                 :            :     0x00000000UL, 0x00003080UL, 0x000E2080UL,
      46                 :            :     0x03C82080UL, 0xFA082080UL, 0x82082080UL
      47                 :            : };
      48                 :            : 
      49                 :            : static const char trailingBytesForUTF8[256] = {
      50                 :            :     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      51                 :            :     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      52                 :            :     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      53                 :            :     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      54                 :            :     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      55                 :            :     0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
      56                 :            :     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
      57                 :            :     2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,4,4,4,4,5,5,5,5
      58                 :            : };
      59                 :            : 
      60                 :            : /* returns length of next utf-8 sequence */
      61                 :   11020760 : size_t u8_seqlen(const char *s)
      62                 :            : {
      63                 :   11020760 :     return trailingBytesForUTF8[(unsigned int)(unsigned char)s[0]] + 1;
      64                 :            : }
      65                 :            : 
      66                 :            : /* returns the # of bytes needed to encode a certain character
      67                 :            :    0 means the character cannot (or should not) be encoded. */
      68                 :          0 : size_t u8_charlen(uint32_t ch)
      69                 :            : {
      70         [ #  # ]:          0 :     if (ch < 0x80)
      71                 :          0 :         return 1;
      72         [ #  # ]:          0 :     else if (ch < 0x800)
      73                 :          0 :         return 2;
      74         [ #  # ]:          0 :     else if (ch < 0x10000)
      75                 :          0 :         return 3;
      76         [ #  # ]:          0 :     else if (ch < 0x110000)
      77                 :          0 :         return 4;
      78                 :          0 :     return 0;
      79                 :            : }
      80                 :            : 
      81                 :            : /* conversions without error checking
      82                 :            :    only works for valid UTF-8, i.e. no 5- or 6-byte sequences
      83                 :            :    srcsz = source size in bytes
      84                 :            :    sz = dest size in # of wide characters
      85                 :            : 
      86                 :            :    returns # characters converted
      87                 :            :    if sz == srcsz+1 (i.e. 4*srcsz+4 bytes), there will always be enough space.
      88                 :            : */
      89                 :          0 : size_t u8_toucs(uint32_t *dest, size_t sz, const char *src, size_t srcsz)
      90                 :            : {
      91                 :            :     uint32_t ch;
      92                 :          0 :     const char *src_end = src + srcsz;
      93                 :            :     size_t nb;
      94                 :          0 :     size_t i=0;
      95                 :            : 
      96   [ #  #  #  # ]:          0 :     if (sz == 0 || srcsz == 0)
      97                 :          0 :         return 0;
      98                 :            : 
      99         [ #  # ]:          0 :     while (i < sz) {
     100         [ #  # ]:          0 :         if (!isutf(*src)) {     // invalid sequence
     101                 :          0 :             dest[i++] = 0xFFFD;
     102                 :          0 :             src++;
     103         [ #  # ]:          0 :             if (src >= src_end) break;
     104                 :          0 :             continue;
     105                 :            :         }
     106                 :          0 :         nb = trailingBytesForUTF8[(unsigned char)*src];
     107         [ #  # ]:          0 :         if (src + nb >= src_end)
     108                 :          0 :             break;
     109                 :          0 :         ch = 0;
     110   [ #  #  #  #  :          0 :         switch (nb) {
                #  #  # ]
     111                 :            :             /* these fall through deliberately */
     112                 :          0 :         case 5: ch += (unsigned char)*src++; ch <<= 6; JL_FALLTHROUGH;
     113                 :          0 :         case 4: ch += (unsigned char)*src++; ch <<= 6; JL_FALLTHROUGH;
     114                 :          0 :         case 3: ch += (unsigned char)*src++; ch <<= 6; JL_FALLTHROUGH;
     115                 :          0 :         case 2: ch += (unsigned char)*src++; ch <<= 6; JL_FALLTHROUGH;
     116                 :          0 :         case 1: ch += (unsigned char)*src++; ch <<= 6; JL_FALLTHROUGH;
     117                 :          0 :         case 0: ch += (unsigned char)*src++;
     118                 :            :         }
     119                 :          0 :         ch -= offsetsFromUTF8[nb];
     120                 :          0 :         dest[i++] = ch;
     121                 :            :     }
     122                 :          0 :     return i;
     123                 :            : }
     124                 :            : 
     125                 :            : /* srcsz = number of source characters
     126                 :            :    sz = size of dest buffer in bytes
     127                 :            : 
     128                 :            :    returns # bytes stored in dest
     129                 :            :    the destination string will never be bigger than the source string.
     130                 :            : */
     131                 :    1642742 : size_t u8_toutf8(char *dest, size_t sz, const uint32_t *src, size_t srcsz)
     132                 :            : {
     133                 :            :     uint32_t ch;
     134                 :    1642742 :     size_t i = 0;
     135                 :    1642742 :     char *dest0 = dest;
     136                 :    1642742 :     char *dest_end = dest + sz;
     137                 :            : 
     138         [ +  + ]:    3285480 :     while (i < srcsz) {
     139                 :    1642742 :         ch = src[i];
     140         [ +  + ]:    1642742 :         if (ch < 0x80) {
     141         [ -  + ]:    1580592 :             if (dest >= dest_end)
     142                 :          0 :                 break;
     143                 :    1580592 :             *dest++ = (char)ch;
     144                 :            :         }
     145         [ +  + ]:      62150 :         else if (ch < 0x800) {
     146         [ -  + ]:      15856 :             if (dest >= dest_end-1)
     147                 :          0 :                 break;
     148                 :      15856 :             *dest++ = (ch>>6) | 0xC0;
     149                 :      15856 :             *dest++ = (ch & 0x3F) | 0x80;
     150                 :            :         }
     151         [ +  + ]:      46294 :         else if (ch < 0x10000) {
     152         [ -  + ]:      29806 :             if (dest >= dest_end-2)
     153                 :          0 :                 break;
     154                 :      29806 :             *dest++ = (ch>>12) | 0xE0;
     155                 :      29806 :             *dest++ = ((ch>>6) & 0x3F) | 0x80;
     156                 :      29806 :             *dest++ = (ch & 0x3F) | 0x80;
     157                 :            :         }
     158         [ +  - ]:      16488 :         else if (ch < 0x110000) {
     159         [ -  + ]:      16488 :             if (dest >= dest_end-3)
     160                 :          0 :                 break;
     161                 :      16488 :             *dest++ = (ch>>18) | 0xF0;
     162                 :      16488 :             *dest++ = ((ch>>12) & 0x3F) | 0x80;
     163                 :      16488 :             *dest++ = ((ch>>6) & 0x3F) | 0x80;
     164                 :      16488 :             *dest++ = (ch & 0x3F) | 0x80;
     165                 :            :         }
     166                 :            :         else {
     167         [ #  # ]:          0 :             if (dest >= dest_end-2)
     168                 :          0 :                 break;
     169                 :            :             // invalid: use replacement char \ufffd
     170                 :          0 :             *dest++ = (char)0xef;
     171                 :          0 :             *dest++ = (char)0xbf;
     172                 :          0 :             *dest++ = (char)0xbd;
     173                 :            :         }
     174                 :    1642742 :         i++;
     175                 :            :     }
     176                 :    1642742 :     return (dest-dest0);
     177                 :            : }
     178                 :            : 
     179                 :        474 : size_t u8_wc_toutf8(char *dest, uint32_t ch)
     180                 :            : {
     181         [ -  + ]:        474 :     if (ch < 0x80) {
     182                 :          0 :         dest[0] = (char)ch;
     183                 :          0 :         return 1;
     184                 :            :     }
     185         [ +  + ]:        474 :     if (ch < 0x800) {
     186                 :         32 :         dest[0] = (ch>>6) | 0xC0;
     187                 :         32 :         dest[1] = (ch & 0x3F) | 0x80;
     188                 :         32 :         return 2;
     189                 :            :     }
     190         [ +  + ]:        442 :     if (ch < 0x10000) {
     191                 :        406 :         dest[0] = (ch>>12) | 0xE0;
     192                 :        406 :         dest[1] = ((ch>>6) & 0x3F) | 0x80;
     193                 :        406 :         dest[2] = (ch & 0x3F) | 0x80;
     194                 :        406 :         return 3;
     195                 :            :     }
     196         [ +  - ]:         36 :     if (ch < 0x110000) {
     197                 :         36 :         dest[0] = (ch>>18) | 0xF0;
     198                 :         36 :         dest[1] = ((ch>>12) & 0x3F) | 0x80;
     199                 :         36 :         dest[2] = ((ch>>6) & 0x3F) | 0x80;
     200                 :         36 :         dest[3] = (ch & 0x3F) | 0x80;
     201                 :         36 :         return 4;
     202                 :            :     }
     203                 :          0 :     dest[0] = (char)0xef;
     204                 :          0 :     dest[1] = (char)0xbf;
     205                 :          0 :     dest[2] = (char)0xbd;
     206                 :          0 :     return 3;
     207                 :            : }
     208                 :            : 
     209                 :            : /* charnum => byte offset */
     210                 :          0 : size_t u8_offset(const char *s, size_t charnum)
     211                 :            : {
     212                 :          0 :     size_t i=0;
     213                 :            : 
     214         [ #  # ]:          0 :     while (charnum > 0) {
     215         [ #  # ]:          0 :         if (s[i++] & 0x80) {
     216   [ #  #  #  #  :          0 :             (void)(isutf(s[++i]) || isutf(s[++i]) || ++i);
                   #  # ]
     217                 :            :         }
     218                 :          0 :         charnum--;
     219                 :            :     }
     220                 :          0 :     return i;
     221                 :            : }
     222                 :            : 
     223                 :            : /* byte offset => charnum */
     224                 :         48 : size_t u8_charnum(const char *s, size_t offset)
     225                 :            : {
     226                 :         48 :     size_t charnum = 0;
     227         [ +  - ]:         48 :     if (offset) {
     228                 :            :        do {
     229                 :            :           // Simply not count continuation bytes
     230                 :            :           // Since we are not doing validation anyway, we can just
     231                 :            :           // assume this is a valid UTF-8 string
     232                 :        892 :           charnum += ((*(unsigned char *)s++ & 0xc0) != 0x80);
     233         [ +  + ]:        892 :        } while (--offset);
     234                 :            :     }
     235                 :         48 :     return charnum;
     236                 :            : }
     237                 :            : 
     238                 :    1770382 : size_t u8_strwidth(const char *s)
     239                 :            : {
     240                 :            :     uint32_t ch;
     241                 :    1770382 :     size_t nb, tot=0;
     242                 :            :     signed char sc;
     243                 :            : 
     244         [ +  + ]:    4199520 :     while ((sc = (signed char)*s) != 0) {
     245         [ +  + ]:    2429140 :         if (sc >= 0) {
     246                 :    2425620 :             s++;
     247         [ +  - ]:    2425620 :             if (sc) tot++;
     248                 :            :         }
     249                 :            :         else {
     250         [ -  + ]:       3526 :             if (!isutf(sc)) { tot++; s++; continue; }
     251                 :       3526 :             nb = trailingBytesForUTF8[(unsigned char)sc];
     252                 :       3526 :             ch = 0;
     253   [ -  -  -  +  :       3526 :             switch (nb) {
                +  -  - ]
     254                 :            :                 /* these fall through deliberately */
     255                 :          0 :             case 5: ch += (unsigned char)*s++; ch <<= 6; JL_FALLTHROUGH;
     256                 :          0 :             case 4: ch += (unsigned char)*s++; ch <<= 6; JL_FALLTHROUGH;
     257                 :          0 :             case 3: ch += (unsigned char)*s++; ch <<= 6; JL_FALLTHROUGH;
     258                 :       3204 :             case 2: ch += (unsigned char)*s++; ch <<= 6; JL_FALLTHROUGH;
     259                 :       3526 :             case 1: ch += (unsigned char)*s++; ch <<= 6; JL_FALLTHROUGH;
     260                 :       3526 :             case 0: ch += (unsigned char)*s++;
     261                 :            :             }
     262                 :       3526 :             ch -= offsetsFromUTF8[nb];
     263                 :       3526 :             tot += utf8proc_charwidth(ch);
     264                 :            :         }
     265                 :            :     }
     266                 :    1770382 :     return tot;
     267                 :            : }
     268                 :            : 
     269                 :            : /* reads the next utf-8 sequence out of a string, updating an index */
     270                 :   10689000 : uint32_t u8_nextchar(const char *s, size_t *i)
     271                 :            : {
     272                 :   10689000 :     uint32_t ch = 0;
     273                 :            :     size_t sz, j;
     274                 :            : 
     275                 :   10689000 :     sz = u8_seqlen(&s[*i]);
     276         [ +  + ]:   21707200 :     for (j = sz; j > 0; j--) {
     277                 :   11018140 :         ch <<= 6;
     278                 :   11018140 :         ch += (unsigned char)s[(*i)++];
     279                 :            :     }
     280                 :   10689000 :     ch -= offsetsFromUTF8[sz-1];
     281                 :            : 
     282                 :   10689000 :     return ch;
     283                 :            : }
     284                 :            : 
     285                 :            : /* next character without NUL character terminator */
     286                 :          0 : uint32_t u8_nextmemchar(const char *s, size_t *i)
     287                 :            : {
     288                 :          0 :     return u8_nextchar(s,i);
     289                 :            : }
     290                 :            : 
     291                 :          0 : void u8_inc(const char *s, size_t *i)
     292                 :            : {
     293   [ #  #  #  #  :          0 :     (void)(isutf(s[++(*i)]) || isutf(s[++(*i)]) || isutf(s[++(*i)]) || ++(*i));
             #  #  #  # ]
     294                 :          0 : }
     295                 :            : 
     296                 :          0 : void u8_dec(const char *s, size_t *i)
     297                 :            : {
     298   [ #  #  #  #  :          0 :     (void)(isutf(s[--(*i)]) || isutf(s[--(*i)]) || isutf(s[--(*i)]) || --(*i));
             #  #  #  # ]
     299                 :          0 : }
     300                 :            : 
     301                 :     131400 : int octal_digit(char c)
     302                 :            : {
     303   [ +  +  +  + ]:     131400 :     return (c >= '0' && c <= '7');
     304                 :            : }
     305                 :            : 
     306                 :     240978 : int hex_digit(char c)
     307                 :            : {
     308   [ +  +  +  + ]:     240978 :     return ((c >= '0' && c <= '9') ||
     309   [ +  +  +  +  :     544134 :             (c >= 'A' && c <= 'F') ||
                   +  + ]
     310         [ +  + ]:      62178 :             (c >= 'a' && c <= 'f'));
     311                 :            : }
     312                 :            : 
     313                 :      50518 : char read_escape_control_char(char c)
     314                 :            : {
     315         [ +  + ]:      50518 :     if (c == 'n')
     316                 :       2220 :         return '\n';
     317         [ +  + ]:      48298 :     else if (c == 't')
     318                 :        148 :         return '\t';
     319         [ +  + ]:      48150 :     else if (c == 'r')
     320                 :        230 :         return '\r';
     321         [ +  + ]:      47920 :     else if (c == 'e')
     322                 :        636 :         return '\x1B';
     323         [ +  + ]:      47284 :     else if (c == 'b')
     324                 :         76 :         return '\b';
     325         [ +  + ]:      47208 :     else if (c == 'f')
     326                 :         12 :         return '\f';
     327         [ +  + ]:      47196 :     else if (c == 'v')
     328                 :          8 :         return '\v';
     329         [ +  + ]:      47188 :     else if (c == 'a')
     330                 :         12 :         return '\a';
     331                 :      47176 :     return c;
     332                 :            : }
     333                 :            : 
     334                 :            : /* assumes that src points to the character after a backslash
     335                 :            :    returns number of input characters processed, 0 if error */
     336                 :          0 : size_t u8_read_escape_sequence(const char *str, size_t ssz, uint32_t *dest)
     337                 :            : {
     338         [ #  # ]:          0 :     assert(ssz > 0);
     339                 :            :     uint32_t ch;
     340                 :            :     char digs[10];
     341                 :          0 :     int dno=0, ndig;
     342                 :          0 :     size_t i=1;
     343                 :          0 :     char c0 = str[0];
     344                 :            : 
     345         [ #  # ]:          0 :     if (octal_digit(c0)) {
     346                 :          0 :         i = 0;
     347                 :            :         do {
     348                 :          0 :             digs[dno++] = str[i++];
     349   [ #  #  #  #  :          0 :         } while (i<ssz && octal_digit(str[i]) && dno<3);
                   #  # ]
     350                 :          0 :         digs[dno] = '\0';
     351                 :          0 :         ch = strtol(digs, NULL, 8);
     352                 :            :     }
     353   [ #  #  #  # ]:          0 :     else if ((c0=='x' && (ndig=2)) ||
     354         [ #  # ]:          0 :              (c0=='u' && (ndig=4)) ||
     355                 :          0 :              (c0=='U' && (ndig=8))) {
     356   [ #  #  #  #  :          0 :         while (i<ssz && hex_digit(str[i]) && dno<ndig) {
                   #  # ]
     357                 :          0 :             digs[dno++] = str[i++];
     358                 :            :         }
     359         [ #  # ]:          0 :         if (dno == 0) return 0;
     360                 :          0 :         digs[dno] = '\0';
     361                 :          0 :         ch = strtol(digs, NULL, 16);
     362                 :            :     }
     363                 :            :     else {
     364                 :          0 :         ch = (uint32_t)read_escape_control_char(c0);
     365                 :            :     }
     366                 :          0 :     *dest = ch;
     367                 :            : 
     368                 :          0 :     return i;
     369                 :            : }
     370                 :            : 
     371                 :          0 : static inline int buf_put2c(char *buf, const char *src)
     372                 :            : {
     373                 :          0 :     buf[0] = src[0];
     374                 :          0 :     buf[1] = src[1];
     375                 :          0 :     buf[2] = '\0';
     376                 :          0 :     return 2;
     377                 :            : }
     378                 :            : 
     379                 :          0 : int u8_escape_wchar(char *buf, size_t sz, uint32_t ch)
     380                 :            : {
     381         [ #  # ]:          0 :     assert(sz > 2);
     382         [ #  # ]:          0 :     if (ch == L'\n')
     383                 :          0 :         return buf_put2c(buf, "\\n");
     384         [ #  # ]:          0 :     else if (ch == L'\t')
     385                 :          0 :         return buf_put2c(buf, "\\t");
     386         [ #  # ]:          0 :     else if (ch == L'\r')
     387                 :          0 :         return buf_put2c(buf, "\\r");
     388         [ #  # ]:          0 :     else if (ch == L'\x1B')
     389                 :          0 :         return buf_put2c(buf, "\\e");
     390         [ #  # ]:          0 :     else if (ch == L'\b')
     391                 :          0 :         return buf_put2c(buf, "\\b");
     392         [ #  # ]:          0 :     else if (ch == L'\f')
     393                 :          0 :         return buf_put2c(buf, "\\f");
     394         [ #  # ]:          0 :     else if (ch == L'\v')
     395                 :          0 :         return buf_put2c(buf, "\\v");
     396         [ #  # ]:          0 :     else if (ch == L'\a')
     397                 :          0 :         return buf_put2c(buf, "\\a");
     398         [ #  # ]:          0 :     else if (ch == L'\\')
     399                 :          0 :         return buf_put2c(buf, "\\\\");
     400   [ #  #  #  # ]:          0 :     else if (ch < 32 || ch == 0x7f)
     401                 :          0 :         return snprintf(buf, sz, "\\x%.2hhx", (unsigned char)ch);
     402         [ #  # ]:          0 :     else if (ch > 0xFFFF)
     403                 :          0 :         return snprintf(buf, sz, "\\U%.8x", (uint32_t)ch);
     404         [ #  # ]:          0 :     else if (ch >= 0x80)
     405                 :          0 :         return snprintf(buf, sz, "\\u%.4hx", (unsigned short)ch);
     406                 :            : 
     407                 :          0 :     buf[0] = (char)ch;
     408                 :          0 :     buf[1] = '\0';
     409                 :          0 :     return 1;
     410                 :            : }
     411                 :            : 
     412                 :          0 : size_t u8_escape(char *buf, size_t sz, const char *src, size_t *pi, size_t end,
     413                 :            :                  int escape_quotes, int ascii)
     414                 :            : {
     415                 :          0 :     size_t i = *pi, i0;
     416                 :            :     uint32_t ch;
     417                 :          0 :     char *start = buf;
     418                 :          0 :     char *blim = start + sz-11;
     419         [ #  # ]:          0 :     assert(sz > 11);
     420                 :            : 
     421   [ #  #  #  # ]:          0 :     while (i<end && buf<blim) {
     422                 :            :         // sz-11: leaves room for longest escape sequence
     423   [ #  #  #  # ]:          0 :         if (escape_quotes && src[i] == '"') {
     424                 :          0 :             buf += buf_put2c(buf, "\\\"");
     425                 :          0 :             i++;
     426                 :            :         }
     427         [ #  # ]:          0 :         else if (src[i] == '\\') {
     428                 :          0 :             buf += buf_put2c(buf, "\\\\");
     429                 :          0 :             i++;
     430                 :            :         }
     431                 :            :         else {
     432                 :          0 :             i0 = i;
     433                 :          0 :             ch = u8_nextmemchar(src, &i);
     434   [ #  #  #  # ]:          0 :             if (ascii || !iswprint((wint_t)ch)) {
     435                 :          0 :                 buf += u8_escape_wchar(buf, sz - (buf-start), ch);
     436                 :            :             }
     437                 :            :             else {
     438                 :          0 :                 i = i0;
     439                 :            :                 do {
     440                 :          0 :                     *buf++ = src[i++];
     441         [ #  # ]:          0 :                 } while (!isutf(src[i]));
     442                 :            :             }
     443                 :            :         }
     444                 :            :     }
     445                 :          0 :     *buf++ = '\0';
     446                 :          0 :     *pi = i;
     447                 :          0 :     return (buf-start);
     448                 :            : }
     449                 :            : 
     450                 :          0 : char *u8_memchr(const char *s, uint32_t ch, size_t sz, size_t *charn)
     451                 :            : {
     452                 :          0 :     size_t i = 0, lasti=0;
     453                 :            :     uint32_t c;
     454                 :            :     int csz;
     455                 :            : 
     456                 :          0 :     *charn = 0;
     457         [ #  # ]:          0 :     while (i < sz) {
     458                 :          0 :         c = csz = 0;
     459                 :            :         do {
     460                 :          0 :             c <<= 6;
     461                 :          0 :             c += (unsigned char)s[i++];
     462                 :          0 :             csz++;
     463   [ #  #  #  # ]:          0 :         } while (i < sz && !isutf(s[i]));
     464                 :          0 :         c -= offsetsFromUTF8[csz-1];
     465                 :            : 
     466         [ #  # ]:          0 :         if (c == ch) {
     467                 :          0 :             return (char*)&s[lasti];
     468                 :            :         }
     469                 :          0 :         lasti = i;
     470                 :          0 :         (*charn)++;
     471                 :            :     }
     472                 :          0 :     return NULL;
     473                 :            : }
     474                 :            : 
     475                 :          0 : char *u8_memrchr(const char *s, uint32_t ch, size_t sz)
     476                 :            : {
     477                 :          0 :     size_t i = sz-1, tempi=0;
     478                 :            :     uint32_t c;
     479                 :            : 
     480         [ #  # ]:          0 :     if (sz == 0) return NULL;
     481                 :            : 
     482   [ #  #  #  # ]:          0 :     while (i && !isutf(s[i])) i--;
     483                 :            : 
     484                 :            :     while (1) {
     485                 :          0 :         tempi = i;
     486                 :          0 :         c = u8_nextmemchar(s, &tempi);
     487         [ #  # ]:          0 :         if (c == ch) {
     488                 :          0 :             return (char*)&s[i];
     489                 :            :         }
     490         [ #  # ]:          0 :         if (i == 0)
     491                 :          0 :             break;
     492                 :          0 :         tempi = i;
     493                 :          0 :         u8_dec(s, &i);
     494         [ #  # ]:          0 :         if (i > tempi)
     495                 :          0 :             break;
     496                 :            :     }
     497                 :          0 :     return NULL;
     498                 :            : }
     499                 :            : 
     500                 :          0 : size_t u8_vprintf(const char *fmt, va_list ap)
     501                 :            : {
     502                 :          0 :     size_t cnt, sz=0, nc, needfree=0;
     503                 :            :     char *buf;
     504                 :            :     uint32_t *wcs;
     505                 :            : 
     506                 :          0 :     sz = 512;
     507                 :          0 :     buf = (char*)alloca(sz);
     508                 :          0 :     cnt = vsnprintf(buf, sz, fmt, ap);
     509         [ #  # ]:          0 :     if ((intptr_t)cnt < 0)
     510                 :          0 :         return 0;
     511         [ #  # ]:          0 :     if (cnt >= sz) {
     512                 :          0 :         buf = (char*)malloc_s(cnt+1);
     513                 :          0 :         needfree = 1;
     514                 :          0 :         vsnprintf(buf, cnt+1, fmt, ap);
     515                 :            :     }
     516                 :          0 :     wcs = (uint32_t*)alloca((cnt+1) * sizeof(uint32_t));
     517                 :          0 :     nc = u8_toucs(wcs, cnt+1, buf, cnt);
     518                 :          0 :     wcs[nc] = 0;
     519                 :          0 :     printf("%ls", (wchar_t*)wcs);
     520         [ #  # ]:          0 :     if (needfree)
     521                 :          0 :         free(buf);
     522                 :          0 :     return nc;
     523                 :            : }
     524                 :            : 
     525                 :          0 : size_t u8_printf(const char *fmt, ...)
     526                 :            : {
     527                 :            :     size_t cnt;
     528                 :            :     va_list args;
     529                 :            : 
     530                 :          0 :     va_start(args, fmt);
     531                 :            : 
     532                 :          0 :     cnt = u8_vprintf(fmt, args);
     533                 :            : 
     534                 :          0 :     va_end(args);
     535                 :          0 :     return cnt;
     536                 :            : }
     537                 :            : 
     538                 :            : /* Rewritten completely, original code not based on anything else
     539                 :            : 
     540                 :            :    length is in bytes, since without knowing whether the string is valid
     541                 :            :    it's hard to know how many characters there are! */
     542                 :     143714 : int u8_isvalid(const char *str, size_t len)
     543                 :            : {
     544                 :            :     const unsigned char *pnt;   // Current pointer in string
     545                 :            :     const unsigned char *pend;  // End of string
     546                 :            :     unsigned char       byt;    // Current byte
     547                 :            : 
     548                 :            :     // Empty strings can be considered valid ASCII
     549         [ -  + ]:     143714 :     if (!len) return 1;
     550                 :     143714 :     pnt = (unsigned char *)str;
     551                 :     143714 :     pend = (unsigned char *)str + len;
     552                 :            :     // First scan for non-ASCII characters as fast as possible
     553                 :            :     do {
     554         [ +  - ]:     143714 :         if (*pnt++ & 0x80) goto chkutf8;
     555         [ #  # ]:          0 :     } while (pnt < pend);
     556                 :          0 :     return 1;
     557                 :            : 
     558                 :            :     // Check validity of UTF-8 sequences
     559                 :     143714 : chkutf8:
     560         [ -  + ]:     143714 :     if (pnt == pend) return 0;    // Last byte can't be > 127
     561                 :     143714 :     byt = pnt[-1];
     562                 :            :     // Must be between 0xc2 and 0xf4 inclusive to be valid
     563         [ -  + ]:     143714 :     if (((uint32_t)byt - 0xc2) > (0xf4-0xc2)) return 0;
     564         [ +  + ]:     143714 :     if (byt < 0xe0) {               // 2-byte sequence
     565                 :            :         // Must have valid continuation character
     566         [ -  + ]:      30954 :         if ((*pnt++ & 0xc0) != 0x80) return 0;
     567         [ +  + ]:     112760 :     } else if (byt < 0xf0) {        // 3-byte sequence
     568         [ +  - ]:      88028 :         if ((pnt + 1 >= pend)
     569         [ +  - ]:      88028 :               || (*pnt & 0xc0) != 0x80
     570         [ -  + ]:      88028 :               || (pnt[1] & 0xc0) != 0x80)
     571                 :          0 :             return 0;
     572                 :            :         // Check for surrogate chars
     573   [ -  +  -  - ]:      88028 :         if (byt == 0xed && *pnt > 0x9f) return 0;
     574                 :            :         // Check for overlong encoding
     575   [ +  +  -  + ]:      88028 :         if (byt == 0xe0 && *pnt < 0xa0) return 0;
     576                 :      88028 :         pnt += 2;
     577                 :            :     } else {                        // 4-byte sequence
     578                 :            :         // Must have 3 valid continuation characters
     579         [ +  - ]:      24732 :         if ((pnt + 2 >= pend)
     580         [ +  - ]:      24732 :               || (*pnt & 0xc0) != 0x80
     581         [ +  - ]:      24732 :               || (pnt[1] & 0xc0) != 0x80
     582         [ -  + ]:      24732 :               || (pnt[2] & 0xc0) != 0x80)
     583                 :          0 :             return 0;
     584                 :            :         // Make sure in correct range (0x10000 - 0x10ffff)
     585         [ +  - ]:      24732 :         if (byt == 0xf0) {
     586         [ -  + ]:      24732 :             if (*pnt < 0x90) return 0;
     587         [ #  # ]:          0 :         } else if (byt == 0xf4) {
     588         [ #  # ]:          0 :             if (*pnt > 0x8f) return 0;
     589                 :            :         }
     590                 :      24732 :         pnt += 3;
     591                 :            :     }
     592                 :            :     // Find next non-ASCII characters as fast as possible
     593         [ -  + ]:     143714 :     while (pnt < pend) {
     594         [ #  # ]:          0 :         if (*pnt++ & 0x80) goto chkutf8;
     595                 :            :     }
     596                 :     143714 :     return 2;   // Valid UTF-8
     597                 :            : }
     598                 :            : #ifdef __cplusplus
     599                 :            : }
     600                 :            : #endif

Generated by: LCOV version 1.14