[MonoIO] Wrap calls to open() in EINTR handling (#21042)
[mono-project.git] / mono / eglib / gunicode.c
blobb8db6b5abd4ee3ffff31bb80ef749d459fbe1658
1 /*
2 * gunicode.c: Some Unicode routines
4 * Author:
5 * Miguel de Icaza (miguel@novell.com)
7 * (C) 2006 Novell, Inc.
9 * utf8 validation code came from:
10 * libxml2-2.6.26 licensed under the MIT X11 license
12 * Authors credit in libxml's string.c:
13 * William Brack <wbrack@mmm.com.hk>
14 * daniel@veillard.com
16 * Permission is hereby granted, free of charge, to any person obtaining
17 * a copy of this software and associated documentation files (the
18 * "Software"), to deal in the Software without restriction, including
19 * without limitation the rights to use, copy, modify, merge, publish,
20 * distribute, sublicense, and/or sell copies of the Software, and to
21 * permit persons to whom the Software is furnished to do so, subject to
22 * the following conditions:
24 * The above copyright notice and this permission notice shall be
25 * included in all copies or substantial portions of the Software.
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
36 #include <config.h>
37 #include <stdio.h>
38 #include <glib.h>
39 #include <unicode-data.h>
40 #include <errno.h>
42 #if !defined (G_OS_WIN32) && HAVE_NL_LANGINFO
43 # include <langinfo.h>
44 #endif
46 const char *eg_my_charset;
49 * Character set conversion
52 GUnicodeType
53 g_unichar_type (gunichar c)
55 int i;
57 guint16 cp = (guint16) c;
58 for (i = 0; i < unicode_category_ranges_count; i++) {
59 if (cp < unicode_category_ranges [i].start)
60 continue;
61 if (unicode_category_ranges [i].end <= cp)
62 continue;
63 return (GUnicodeType)(unicode_category [i] [cp - unicode_category_ranges [i].start]);
67 // 3400-4DB5: OtherLetter
68 // 4E00-9FC3: OtherLetter
69 // AC00-D7A3: OtherLetter
70 // D800-DFFF: OtherSurrogate
71 // E000-F8FF: OtherPrivateUse
72 // 20000-2A6D6 OtherLetter
73 // F0000-FFFFD OtherPrivateUse
74 // 100000-10FFFD OtherPrivateUse
76 if (0x3400 <= cp && cp < 0x4DB5)
77 return G_UNICODE_OTHER_LETTER;
78 if (0x4E00 <= cp && cp < 0x9FC3)
79 return G_UNICODE_OTHER_LETTER;
80 if (0xAC00<= cp && cp < 0xD7A3)
81 return G_UNICODE_OTHER_LETTER;
82 if (0xD800 <= cp && cp < 0xDFFF)
83 return G_UNICODE_SURROGATE;
84 if (0xE000 <= cp && cp < 0xF8FF)
85 return G_UNICODE_PRIVATE_USE;
86 /* since the argument is UTF-16, we cannot check beyond FFFF */
88 /* It should match any of above */
89 return (GUnicodeType)0; // G_UNICODE_CONTROL
92 GUnicodeBreakType
93 g_unichar_break_type (gunichar c)
95 // MOONLIGHT_FIXME
96 return G_UNICODE_BREAK_UNKNOWN;
99 static gunichar
100 g_unichar_case (gunichar c, gboolean upper)
102 gint8 i, i2;
103 guint32 cp = (guint32) c, v;
105 for (i = 0; i < simple_case_map_ranges_count; i++) {
106 if (cp < simple_case_map_ranges [i].start)
107 return c;
108 if (simple_case_map_ranges [i].end <= cp)
109 continue;
110 if (c < 0x10000) {
111 const guint16 *tab = upper ? simple_upper_case_mapping_lowarea [i] : simple_lower_case_mapping_lowarea [i];
112 v = tab [cp - simple_case_map_ranges [i].start];
113 } else {
114 const guint32 *tab;
115 i2 = (gint8)(i - (upper ? simple_upper_case_mapping_lowarea_table_count : simple_lower_case_mapping_lowarea_table_count));
116 tab = upper ? simple_upper_case_mapping_higharea [i2] : simple_lower_case_mapping_higharea [i2];
117 v = tab [cp - simple_case_map_ranges [i].start];
119 return v != 0 ? (gunichar) v : c;
121 return c;
124 gunichar
125 g_unichar_toupper (gunichar c)
127 return g_unichar_case (c, TRUE);
130 gunichar
131 g_unichar_tolower (gunichar c)
133 return g_unichar_case (c, FALSE);
136 gunichar
137 g_unichar_totitle (gunichar c)
139 guint8 i;
140 guint32 cp;
142 cp = (guint32) c;
143 for (i = 0; i < simple_titlecase_mapping_count; i++) {
144 if (simple_titlecase_mapping [i].codepoint == cp)
145 return simple_titlecase_mapping [i].title;
146 if (simple_titlecase_mapping [i].codepoint > cp)
147 /* it is ordered, hence no more match */
148 break;
150 return g_unichar_toupper (c);
153 gboolean
154 g_unichar_isxdigit (gunichar c)
156 return (g_unichar_xdigit_value (c) != -1);
160 gint
161 g_unichar_xdigit_value (gunichar c)
163 if (c >= 0x30 && c <= 0x39) /*0-9*/
164 return (c - 0x30);
165 if (c >= 0x41 && c <= 0x46) /*A-F*/
166 return (c - 0x37);
167 if (c >= 0x61 && c <= 0x66) /*a-f*/
168 return (c - 0x57);
169 return -1;
172 gboolean
173 g_unichar_isspace (gunichar c)
175 GUnicodeType type = g_unichar_type (c);
176 if (type == G_UNICODE_LINE_SEPARATOR ||
177 type == G_UNICODE_PARAGRAPH_SEPARATOR ||
178 type == G_UNICODE_SPACE_SEPARATOR)
179 return TRUE;
181 return FALSE;
186 * This is broken, and assumes an UTF8 system, but will do for eglib's first user
188 gchar *
189 g_filename_from_utf8 (const gchar *utf8string, gssize len, gsize *bytes_read, gsize *bytes_written, GError **gerror)
191 char *res;
193 if (len == -1)
194 len = strlen (utf8string);
196 res = g_malloc (len + 1);
197 g_strlcpy (res, utf8string, len + 1);
198 return res;
201 #ifndef G_OS_WIN32
202 static gboolean is_utf8;
204 gboolean
205 g_get_charset (G_CONST_RETURN char **charset)
207 if (eg_my_charset == NULL) {
208 /* These shouldn't be heap allocated */
209 #if HAVE_NL_LANGINFO
211 * This function used used to use the "locale_charset" call in
212 * libiconv's libcharset library. However, this isn't always
213 * available on some systems, including ones with GNU libc. So,
214 * instead use a function that's a standard part of POSIX2008.
216 * nl_langinfo is in POSIX2008 and should be on any sane modern
217 * Unix. With a UTF-8 locale, it should return "UTF-8" - this
218 * has been verified with Ubuntu 18.04, FreeBSD 11, and i 7.3.
220 * The motivation for using locale_charset was likely due to
221 * the cruftiness of Unices back in ~2001; where you had to
222 * manually query environment variables, and the values were
223 * inconsistent between each other. Nowadays, if Linux, macOS,
224 * AIX/PASE, and FreeBSD can all return the same values for a
225 * UTF-8 locale, we can just use the value directly.
227 * It should be noted that by default, this function will give
228 * values for the "C" locale, unless `setlocale (LC_ALL, "")`
229 * is ran to init locales - driver.c in mini does this for us.
231 eg_my_charset = nl_langinfo (CODESET);
232 #else
233 eg_my_charset = "UTF-8";
234 #endif
235 is_utf8 = strcmp (eg_my_charset, "UTF-8") == 0;
238 if (charset != NULL)
239 *charset = eg_my_charset;
241 return is_utf8;
243 #endif /* G_OS_WIN32 */
245 gchar *
246 g_locale_to_utf8 (const gchar *opsysstring, gssize len, gsize *bytes_read, gsize *bytes_written, GError **gerror)
248 g_get_charset (NULL);
250 return g_convert (opsysstring, len, "UTF-8", eg_my_charset, bytes_read, bytes_written, gerror);
253 gchar *
254 g_locale_from_utf8 (const gchar *utf8string, gssize len, gsize *bytes_read, gsize *bytes_written, GError **gerror)
256 g_get_charset (NULL);
258 return g_convert (utf8string, len, eg_my_charset, "UTF-8", bytes_read, bytes_written, gerror);