Mercurial > gnulib
annotate lib/unistr/u32-to-u8.c @ 40057:b06060465f09
maint: Run 'make update-copyright'
author | Paul Eggert <eggert@cs.ucla.edu> |
---|---|
date | Tue, 01 Jan 2019 00:25:11 +0100 |
parents | 10eb9086bea0 |
children |
rev | line source |
---|---|
7811 | 1 /* Convert UTF-32 string to UTF-8 string. |
40057
b06060465f09
maint: Run 'make update-copyright'
Paul Eggert <eggert@cs.ucla.edu>
parents:
19484
diff
changeset
|
2 Copyright (C) 2002, 2006-2007, 2009-2019 Free Software Foundation, Inc. |
7811 | 3 Written by Bruno Haible <bruno@clisp.org>, 2002. |
4 | |
9307
ad8a75a45dc9
Change copyright notice from LGPLv2.0+ to LGPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
8038
diff
changeset
|
5 This program is free software: you can redistribute it and/or modify it |
ad8a75a45dc9
Change copyright notice from LGPLv2.0+ to LGPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
8038
diff
changeset
|
6 under the terms of the GNU Lesser General Public License as published |
ad8a75a45dc9
Change copyright notice from LGPLv2.0+ to LGPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
8038
diff
changeset
|
7 by the Free Software Foundation; either version 3 of the License, or |
ad8a75a45dc9
Change copyright notice from LGPLv2.0+ to LGPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
8038
diff
changeset
|
8 (at your option) any later version. |
7811 | 9 |
10 This program is distributed in the hope that it will be useful, | |
11 but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
9307
ad8a75a45dc9
Change copyright notice from LGPLv2.0+ to LGPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
8038
diff
changeset
|
13 Lesser General Public License for more details. |
7811 | 14 |
9307
ad8a75a45dc9
Change copyright notice from LGPLv2.0+ to LGPLv3+.
Bruno Haible <bruno@clisp.org>
parents:
8038
diff
changeset
|
15 You should have received a copy of the GNU Lesser General Public License |
19190 | 16 along with this program. If not, see <https://www.gnu.org/licenses/>. */ |
7811 | 17 |
18 #include <config.h> | |
19 | |
20 /* Specification. */ | |
21 #include "unistr.h" | |
22 | |
23 #define FUNC u32_to_u8 | |
24 #define SRC_UNIT uint32_t | |
25 #define DST_UNIT uint8_t | |
26 | |
27 #include <errno.h> | |
28 #include <stdlib.h> | |
29 #include <string.h> | |
30 | |
31 DST_UNIT * | |
32 FUNC (const SRC_UNIT *s, size_t n, DST_UNIT *resultbuf, size_t *lengthp) | |
33 { | |
34 const SRC_UNIT *s_end = s + n; | |
35 /* Output string accumulator. */ | |
36 DST_UNIT *result; | |
37 size_t allocated; | |
38 size_t length; | |
39 | |
40 if (resultbuf != NULL) | |
41 { | |
42 result = resultbuf; | |
43 allocated = *lengthp; | |
44 } | |
45 else | |
46 { | |
47 result = NULL; | |
48 allocated = 0; | |
49 } | |
50 length = 0; | |
51 /* Invariants: | |
52 result is either == resultbuf or == NULL or malloc-allocated. | |
53 If length > 0, then result != NULL. */ | |
54 | |
55 while (s < s_end) | |
56 { | |
57 ucs4_t uc; | |
58 int count; | |
59 | |
60 /* Fetch a Unicode character from the input string. */ | |
61 uc = *s++; | |
8038
476e04edf8c6
Rename u32-mbtouc-safe -> u32-mbtouc, u32_mbtouc_safe -> u32_mbtouc.
Bruno Haible <bruno@clisp.org>
parents:
7943
diff
changeset
|
62 /* No need to call the safe variant u32_mbtouc, because |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
63 u8_uctomb will verify uc anyway. */ |
7811 | 64 |
65 /* Store it in the output string. */ | |
7943 | 66 count = u8_uctomb (result + length, uc, allocated - length); |
7811 | 67 if (count == -1) |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
68 { |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
69 if (!(result == resultbuf || result == NULL)) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
70 free (result); |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
71 errno = EILSEQ; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
72 return NULL; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
73 } |
7811 | 74 if (count == -2) |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
75 { |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
76 DST_UNIT *memory; |
7811 | 77 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
78 allocated = (allocated > 0 ? 2 * allocated : 12); |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
79 if (length + 6 > allocated) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
80 allocated = length + 6; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
81 if (result == resultbuf || result == NULL) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
82 memory = (DST_UNIT *) malloc (allocated * sizeof (DST_UNIT)); |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
83 else |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
84 memory = |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
85 (DST_UNIT *) realloc (result, allocated * sizeof (DST_UNIT)); |
7811 | 86 |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
87 if (memory == NULL) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
88 { |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
89 if (!(result == resultbuf || result == NULL)) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
90 free (result); |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
91 errno = ENOMEM; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
92 return NULL; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
93 } |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
94 if (result == resultbuf && length > 0) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
95 memcpy ((char *) memory, (char *) result, |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
96 length * sizeof (DST_UNIT)); |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
97 result = memory; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
98 count = u8_uctomb (result + length, uc, allocated - length); |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
99 if (count < 0) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
100 abort (); |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
101 } |
7811 | 102 length += count; |
103 } | |
104 | |
105 if (length == 0) | |
106 { | |
107 if (result == NULL) | |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
108 { |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
109 /* Return a non-NULL value. NULL means error. */ |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
110 result = (DST_UNIT *) malloc (1); |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
111 if (result == NULL) |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
112 { |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
113 errno = ENOMEM; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
114 return NULL; |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
115 } |
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
116 } |
7811 | 117 } |
118 else if (result != resultbuf && length < allocated) | |
119 { | |
120 /* Shrink the allocated memory if possible. */ | |
121 DST_UNIT *memory; | |
122 | |
123 memory = (DST_UNIT *) realloc (result, length * sizeof (DST_UNIT)); | |
124 if (memory != NULL) | |
12421
e8d2c6fc33ad
Use spaces for indentation, not tabs.
Bruno Haible <bruno@clisp.org>
parents:
9307
diff
changeset
|
125 result = memory; |
7811 | 126 } |
127 | |
128 *lengthp = length; | |
129 return result; | |
130 } |