New module 'unicase/u32-casecoll'.
[gnulib.git] / lib / unicase / u-casexfrm.h
1 /* Locale dependent transformation for case insensitive comparison of Unicode
2    strings.
3    Copyright (C) 2009 Free Software Foundation, Inc.
4    Written by Bruno Haible <bruno@clisp.org>, 2009.
5
6    This program is free software: you can redistribute it and/or modify it
7    under the terms of the GNU Lesser General Public License as published
8    by the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14    Lesser General Public License for more details.
15
16    You should have received a copy of the GNU Lesser General Public License
17    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
18
19 char *
20 FUNC (const UNIT *s, size_t n, const char *iso639_language, uninorm_t nf,
21       char *resultbuf, size_t *lengthp)
22 {
23   UNIT foldedsbuf[2048 / sizeof (UNIT)];
24   UNIT *foldeds;
25   size_t foldeds_length;
26   char convsbuf[2048];
27   char *convs;
28   size_t convs_length;
29   int ret;
30   char *result;
31
32   /* Casefold and normalize the Unicode string.  */
33   foldeds_length = sizeof (foldedsbuf) / sizeof (UNIT);
34   foldeds = U_CASEFOLD (s, n, iso639_language, nf, foldedsbuf, &foldeds_length);
35   if (foldeds == NULL)
36     /* errno is set here.  */
37     return NULL;
38
39   /* Convert it to locale encoding.  */
40   convs = convsbuf;
41   convs_length = sizeof (convsbuf) - 1;
42   ret = U_CONV_TO_ENCODING (locale_charset (),
43                             iconveh_error,
44                             foldeds, foldeds_length,
45                             NULL,
46                             &convs, &convs_length);
47   if (ret < 0)
48     {
49       if (foldeds != foldedsbuf)
50         {
51           int saved_errno = errno;
52           free (foldeds);
53           errno = saved_errno;
54         }
55       return NULL;
56     }
57
58   if (foldeds != foldedsbuf)
59     free (foldeds);
60
61   /* Ensure one more byte is available.  */
62   if (convs != convsbuf)
63     {
64       char *memory = (char *) realloc (convs, convs_length + 1);
65       if (memory == NULL)
66         {
67           free (convs);
68           errno = ENOMEM;
69           return NULL;
70         }
71       convs = memory;
72     }
73
74   /* Apply locale dependent transformations for comparison.  */
75   result = memxfrm (convs, convs_length, resultbuf, lengthp);
76   if (result == NULL)
77     {
78       if (convs != convsbuf)
79         {
80           int saved_errno = errno;
81           free (convs);
82           errno = saved_errno;
83         }
84       return NULL;
85     }
86
87   if (convs != convsbuf)
88     free (convs);
89   return result;
90 }