root/maint/gnulib/lib/unigbrk/ulc-grapheme-breaks.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. is_utf8_encoding
  2. ascii_grapheme_breaks
  3. ulc_grapheme_breaks

   1 /* Grapheme cluster breaks function.
   2    Copyright (C) 2001-2003, 2006-2021 Free Software Foundation, Inc.
   3    Written by Ben Pfaff <blp@cs.stanford.edu>, 2010,
   4    based on code written by Bruno Haible <bruno@clisp.org>, 2009.
   5 
   6    This file is free software.
   7    It is dual-licensed under "the GNU LGPLv3+ or the GNU GPLv2+".
   8    You can redistribute it and/or modify it under either
   9      - the terms of the GNU Lesser General Public License as published
  10        by the Free Software Foundation; either version 3, or (at your
  11        option) any later version, or
  12      - the terms of the GNU General Public License as published by the
  13        Free Software Foundation; either version 2, or (at your option)
  14        any later version, or
  15      - the same dual license "the GNU LGPLv3+ or the GNU GPLv2+".
  16 
  17    This file is distributed in the hope that it will be useful,
  18    but WITHOUT ANY WARRANTY; without even the implied warranty of
  19    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  20    Lesser General Public License and the GNU General Public License
  21    for more details.
  22 
  23    You should have received a copy of the GNU Lesser General Public
  24    License and of the GNU General Public License along with this
  25    program.  If not, see <https://www.gnu.org/licenses/>.  */
  26 
  27 #include <config.h>
  28 
  29 /* Specification.  */
  30 #include "unigbrk.h"
  31 
  32 #include <stdlib.h>
  33 #include <string.h>
  34 
  35 #include "c-ctype.h"
  36 #include "c-strcaseeq.h"
  37 #include "localcharset.h"
  38 #include "uniconv.h"
  39 
  40 static int
  41 is_utf8_encoding (const char *encoding)
     /* [previous][next][first][last][top][bottom][index][help] */
  42 {
  43   if (STRCASEEQ (encoding, "UTF-8", 'U', 'T', 'F', '-', '8', 0, 0, 0, 0))
  44     return 1;
  45   return 0;
  46 }
  47 
  48 #if C_CTYPE_ASCII
  49 /* Assume that every ASCII character starts a new grapheme, which is often
  50    true, except that CR-LF is a single grapheme. */
  51 static void
  52 ascii_grapheme_breaks (const char *s, size_t n, char *p)
     /* [previous][next][first][last][top][bottom][index][help] */
  53 {
  54   size_t i;
  55 
  56   p[0] = 1;
  57   for (i = 1; i < n; i++)
  58     {
  59       bool is_ascii = c_isprint (s[i]) || c_isspace (s[i]);
  60       p[i] = is_ascii && (s[i] != '\n' || s[i - 1] != '\r');
  61     }
  62 }
  63 #endif
  64 
  65 /* Grapheme boundaries in a string in an arbitrary encoding.
  66 
  67    We convert the input string to Unicode.
  68 
  69    The standardized Unicode encodings are UTF-8, UCS-2, UCS-4, UTF-16,
  70    UTF-16BE, UTF-16LE, UTF-7.  UCS-2 supports only characters up to
  71    \U0000FFFF.  UTF-16 and variants support only characters up to
  72    \U0010FFFF.  UTF-7 is way too complex and not supported by glibc-2.1.
  73    UCS-4 specification leaves doubts about endianness and byte order mark.
  74    glibc currently interprets it as big endian without byte order mark,
  75    but this is not backed by an RFC.  So we use UTF-8. It supports
  76    characters up to \U7FFFFFFF and is unambiguously defined.  */
  77 
  78 void
  79 ulc_grapheme_breaks (const char *s, size_t n, char *p)
     /* [previous][next][first][last][top][bottom][index][help] */
  80 {
  81   if (n > 0)
  82     {
  83       const char *encoding = locale_charset ();
  84 
  85       if (is_utf8_encoding (encoding))
  86         u8_grapheme_breaks ((const uint8_t *) s, n, p);
  87       else
  88         {
  89           /* Convert the string to UTF-8 and build a translation table
  90              from offsets into s to offsets into the translated string.  */
  91           size_t *offsets = (size_t *) malloc (n * sizeof (size_t));
  92 
  93           if (offsets != NULL)
  94             {
  95               uint8_t *t;
  96               size_t m;
  97 
  98               t = u8_conv_from_encoding (encoding, iconveh_question_mark,
  99                                          s, n, offsets, NULL, &m);
 100               if (t != NULL)
 101                 {
 102                   char *q = (char *) (m > 0 ? malloc (m) : NULL);
 103 
 104                   if (m == 0 || q != NULL)
 105                     {
 106                       size_t i;
 107 
 108                       /* Determine the grapheme breaks of the UTF-8 string.  */
 109                       u8_grapheme_breaks (t, m, q);
 110 
 111                       /* Translate the result back to the original string.  */
 112                       memset (p, 0, n);
 113                       for (i = 0; i < n; i++)
 114                         if (offsets[i] != (size_t)(-1))
 115                           p[i] = q[offsets[i]];
 116 
 117                       free (q);
 118                       free (t);
 119                       free (offsets);
 120                       return;
 121                     }
 122                   free (t);
 123                 }
 124               free (offsets);
 125             }
 126 
 127           /* Impossible to convert. */
 128 #if C_CTYPE_ASCII
 129           /* Fall back to ASCII as best we can. */
 130           ascii_grapheme_breaks (s, n, p);
 131 #else
 132           /* We cannot make any assumptions. */
 133           p[0] = 1;
 134           memset (p + 1, 0, n - 1);
 135 #endif
 136         }
 137     }
 138 }

/* [previous][next][first][last][top][bottom][index][help] */