blob: 3a93649b9d3fbadc42ab58429fd82ddd1bae9d0b [file] [log] [blame]
Bram Moolenaaredf3f972016-08-29 22:49:24 +02001/* vi:set ts=8 sts=4 sw=4 noet:
Bram Moolenaarab79bcb2004-07-18 21:34:53 +00002 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9/*
10 * os_mac_conv.c: Code specifically for Mac string conversions.
11 *
12 * This code has been put in a separate file to avoid the conflicts that are
13 * caused by including both the X11 and Carbon header files.
14 */
15
16#define NO_X11_INCLUDES
Bram Moolenaar9a4d7fd2011-06-13 02:04:00 +020017
Bram Moolenaarab79bcb2004-07-18 21:34:53 +000018#include "vim.h"
Bram Moolenaar3e96c3d2016-01-29 23:46:21 +010019
Bram Moolenaar097148e2020-08-11 21:58:20 +020020#if !defined(PROTO)
Bram Moolenaar164fca32010-07-14 13:58:07 +020021# include <CoreServices/CoreServices.h>
22#endif
23
Bram Moolenaarab79bcb2004-07-18 21:34:53 +000024
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +000025#if defined(MACOS_CONVERT) || defined(PROTO)
Bram Moolenaar164fca32010-07-14 13:58:07 +020026
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +000027# ifdef PROTO
Bram Moolenaar0f873732019-12-05 20:28:46 +010028// A few dummy types to be able to generate function prototypes.
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +000029typedef int UniChar;
30typedef int *TECObjectRef;
31typedef int CFStringRef;
32# endif
33
Bram Moolenaarbaaa7e92016-01-29 22:47:03 +010034static char_u *mac_utf16_to_utf8(UniChar *from, size_t fromLen, size_t *actualLen);
35static UniChar *mac_utf8_to_utf16(char_u *from, size_t fromLen, size_t *actualLen);
Bram Moolenaar26a60b42005-02-22 08:49:11 +000036
Bram Moolenaar0f873732019-12-05 20:28:46 +010037// Converter for composing decomposed HFS+ file paths
Bram Moolenaar26a60b42005-02-22 08:49:11 +000038static TECObjectRef gPathConverter;
Bram Moolenaar0f873732019-12-05 20:28:46 +010039// Converter used by mac_utf16_to_utf8
Bram Moolenaar26a60b42005-02-22 08:49:11 +000040static TECObjectRef gUTF16ToUTF8Converter;
41
Bram Moolenaarab79bcb2004-07-18 21:34:53 +000042/*
43 * A Mac version of string_convert_ext() for special cases.
44 */
45 char_u *
Bram Moolenaar05540972016-01-30 20:31:25 +010046mac_string_convert(
47 char_u *ptr,
48 int len,
49 int *lenp,
50 int fail_on_error,
51 int from_enc,
52 int to_enc,
53 int *unconvlenp)
Bram Moolenaarab79bcb2004-07-18 21:34:53 +000054{
55 char_u *retval, *d;
56 CFStringRef cfstr;
57 int buflen, in, out, l, i;
58 CFStringEncoding from;
59 CFStringEncoding to;
60
61 switch (from_enc)
62 {
63 case 'l': from = kCFStringEncodingISOLatin1; break;
64 case 'm': from = kCFStringEncodingMacRoman; break;
65 case 'u': from = kCFStringEncodingUTF8; break;
66 default: return NULL;
67 }
68 switch (to_enc)
69 {
70 case 'l': to = kCFStringEncodingISOLatin1; break;
71 case 'm': to = kCFStringEncodingMacRoman; break;
72 case 'u': to = kCFStringEncodingUTF8; break;
73 default: return NULL;
74 }
75
76 if (unconvlenp != NULL)
77 *unconvlenp = 0;
78 cfstr = CFStringCreateWithBytes(NULL, ptr, len, from, 0);
79
Bram Moolenaar62dbdc42011-10-20 18:24:22 +020080 if (cfstr == NULL)
Bram Moolenaar26a60b42005-02-22 08:49:11 +000081 fprintf(stderr, "Encoding failed\n");
Bram Moolenaar0f873732019-12-05 20:28:46 +010082 // When conversion failed, try excluding bytes from the end, helps when
83 // there is an incomplete byte sequence. Only do up to 6 bytes to avoid
84 // looping a long time when there really is something unconvertible.
Bram Moolenaarab79bcb2004-07-18 21:34:53 +000085 while (cfstr == NULL && unconvlenp != NULL && len > 1 && *unconvlenp < 6)
86 {
87 --len;
88 ++*unconvlenp;
89 cfstr = CFStringCreateWithBytes(NULL, ptr, len, from, 0);
90 }
91 if (cfstr == NULL)
92 return NULL;
Bram Moolenaar26a60b42005-02-22 08:49:11 +000093
Bram Moolenaarab79bcb2004-07-18 21:34:53 +000094 if (to == kCFStringEncodingUTF8)
95 buflen = len * 6 + 1;
96 else
97 buflen = len + 1;
98 retval = alloc(buflen);
99 if (retval == NULL)
100 {
101 CFRelease(cfstr);
102 return NULL;
103 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000104
105#if 0
106 CFRange convertRange = CFRangeMake(0, CFStringGetLength(cfstr));
Bram Moolenaar0f873732019-12-05 20:28:46 +0100107 // Determine output buffer size
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000108 CFStringGetBytes(cfstr, convertRange, to, NULL, FALSE, NULL, 0, (CFIndex *)&buflen);
109 retval = (buflen > 0) ? alloc(buflen) : NULL;
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000110 if (retval == NULL)
111 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000112 CFRelease(cfstr);
113 return NULL;
114 }
115
116 if (lenp)
117 *lenp = buflen / sizeof(char_u);
118
119 if (!CFStringGetBytes(cfstr, convertRange, to, NULL, FALSE, retval, buflen, NULL))
120#endif
Bram Moolenaarda2303d2005-08-30 21:55:26 +0000121 if (!CFStringGetCString(cfstr, (char *)retval, buflen, to))
Bram Moolenaarab79bcb2004-07-18 21:34:53 +0000122 {
123 CFRelease(cfstr);
124 if (fail_on_error)
125 {
126 vim_free(retval);
127 return NULL;
128 }
129
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000130 fprintf(stderr, "Trying char-by-char conversion...\n");
Bram Moolenaar0f873732019-12-05 20:28:46 +0100131 // conversion failed for the whole string, but maybe it will work
132 // for each character
Bram Moolenaarab79bcb2004-07-18 21:34:53 +0000133 for (d = retval, in = 0, out = 0; in < len && out < buflen - 1;)
134 {
135 if (from == kCFStringEncodingUTF8)
Bram Moolenaar0fa313a2005-08-10 21:07:57 +0000136 l = utf_ptr2len(ptr + in);
Bram Moolenaarab79bcb2004-07-18 21:34:53 +0000137 else
138 l = 1;
139 cfstr = CFStringCreateWithBytes(NULL, ptr + in, l, from, 0);
140 if (cfstr == NULL)
141 {
142 *d++ = '?';
143 out++;
144 }
145 else
146 {
Bram Moolenaarda2303d2005-08-30 21:55:26 +0000147 if (!CFStringGetCString(cfstr, (char *)d, buflen - out, to))
Bram Moolenaarab79bcb2004-07-18 21:34:53 +0000148 {
149 *d++ = '?';
150 out++;
151 }
152 else
153 {
Bram Moolenaarda2303d2005-08-30 21:55:26 +0000154 i = STRLEN(d);
Bram Moolenaarab79bcb2004-07-18 21:34:53 +0000155 d += i;
156 out += i;
157 }
158 CFRelease(cfstr);
159 }
160 in += l;
161 }
162 *d = NUL;
163 if (lenp != NULL)
164 *lenp = out;
165 return retval;
166 }
167 CFRelease(cfstr);
168 if (lenp != NULL)
Bram Moolenaarda2303d2005-08-30 21:55:26 +0000169 *lenp = STRLEN(retval);
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000170
Bram Moolenaarab79bcb2004-07-18 21:34:53 +0000171 return retval;
172}
173
174/*
175 * Conversion from Apple MacRoman char encoding to UTF-8 or latin1, using
176 * standard Carbon framework.
177 * Input: "ptr[*sizep]".
178 * "real_size" is the size of the buffer that "ptr" points to.
179 * output is in-place, "sizep" is adjusted.
180 * Returns OK or FAIL.
181 */
182 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100183macroman2enc(
184 char_u *ptr,
185 long *sizep,
186 long real_size)
Bram Moolenaarab79bcb2004-07-18 21:34:53 +0000187{
188 CFStringRef cfstr;
189 CFRange r;
190 CFIndex len = *sizep;
191
Bram Moolenaar0f873732019-12-05 20:28:46 +0100192 // MacRoman is an 8-bit encoding, no need to move bytes to
193 // conv_rest[].
Bram Moolenaarab79bcb2004-07-18 21:34:53 +0000194 cfstr = CFStringCreateWithBytes(NULL, ptr, len,
195 kCFStringEncodingMacRoman, 0);
196 /*
197 * If there is a conversion error, try using another
198 * conversion.
199 */
200 if (cfstr == NULL)
201 return FAIL;
202
203 r.location = 0;
204 r.length = CFStringGetLength(cfstr);
205 if (r.length != CFStringGetBytes(cfstr, r,
206 (enc_utf8) ? kCFStringEncodingUTF8 : kCFStringEncodingISOLatin1,
Bram Moolenaar0f873732019-12-05 20:28:46 +0100207 0, // no lossy conversion
208 0, // not external representation
Bram Moolenaarab79bcb2004-07-18 21:34:53 +0000209 ptr + *sizep, real_size - *sizep, &len))
210 {
211 CFRelease(cfstr);
212 return FAIL;
213 }
214 CFRelease(cfstr);
215 mch_memmove(ptr, ptr + *sizep, len);
216 *sizep = len;
217
218 return OK;
219}
220
221/*
222 * Conversion from UTF-8 or latin1 to MacRoman.
223 * Input: "from[fromlen]"
224 * Output: "to[maxtolen]" length in "*tolenp"
225 * Unconverted rest in rest[*restlenp].
226 * Returns OK or FAIL.
227 */
228 int
Bram Moolenaar05540972016-01-30 20:31:25 +0100229enc2macroman(
230 char_u *from,
231 size_t fromlen,
232 char_u *to,
233 int *tolenp,
234 int maxtolen,
235 char_u *rest,
236 int *restlenp)
Bram Moolenaarab79bcb2004-07-18 21:34:53 +0000237{
238 CFStringRef cfstr;
239 CFRange r;
240 CFIndex l;
241
242 *restlenp = 0;
243 cfstr = CFStringCreateWithBytes(NULL, from, fromlen,
244 (enc_utf8) ? kCFStringEncodingUTF8 : kCFStringEncodingISOLatin1,
245 0);
246 while (cfstr == NULL && *restlenp < 3 && fromlen > 1)
247 {
248 rest[*restlenp++] = from[--fromlen];
249 cfstr = CFStringCreateWithBytes(NULL, from, fromlen,
250 (enc_utf8) ? kCFStringEncodingUTF8 : kCFStringEncodingISOLatin1,
251 0);
252 }
253 if (cfstr == NULL)
254 return FAIL;
255
256 r.location = 0;
257 r.length = CFStringGetLength(cfstr);
258 if (r.length != CFStringGetBytes(cfstr, r,
259 kCFStringEncodingMacRoman,
Bram Moolenaar0f873732019-12-05 20:28:46 +0100260 0, // no lossy conversion
261 0, // not external representation (since vim
Dominique Pelleaf4a61a2021-12-27 17:21:41 +0000262 // handles this internally)
Bram Moolenaarab79bcb2004-07-18 21:34:53 +0000263 to, maxtolen, &l))
264 {
265 CFRelease(cfstr);
266 return FAIL;
267 }
268 CFRelease(cfstr);
269 *tolenp = l;
270 return OK;
271}
Bram Moolenaar5eb86f92004-07-26 12:53:41 +0000272
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000273/*
274 * Initializes text converters
275 */
276 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100277mac_conv_init(void)
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000278{
279 TextEncoding utf8_encoding;
280 TextEncoding utf8_hfsplus_encoding;
281 TextEncoding utf8_canon_encoding;
282 TextEncoding utf16_encoding;
283
284 utf8_encoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
285 kTextEncodingDefaultVariant, kUnicodeUTF8Format);
286 utf8_hfsplus_encoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
287 kUnicodeHFSPlusCompVariant, kUnicodeUTF8Format);
288 utf8_canon_encoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
289 kUnicodeCanonicalCompVariant, kUnicodeUTF8Format);
290 utf16_encoding = CreateTextEncoding(kTextEncodingUnicodeDefault,
291 kTextEncodingDefaultVariant, kUnicode16BitFormat);
292
293 if (TECCreateConverter(&gPathConverter, utf8_encoding,
294 utf8_hfsplus_encoding) != noErr)
295 gPathConverter = NULL;
296
297 if (TECCreateConverter(&gUTF16ToUTF8Converter, utf16_encoding,
298 utf8_canon_encoding) != noErr)
Bram Moolenaar19a09a12005-03-04 23:39:37 +0000299 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100300 // On pre-10.3, Unicode normalization is not available so
301 // fall back to non-normalizing converter
Bram Moolenaar19a09a12005-03-04 23:39:37 +0000302 if (TECCreateConverter(&gUTF16ToUTF8Converter, utf16_encoding,
303 utf8_encoding) != noErr)
304 gUTF16ToUTF8Converter = NULL;
305 }
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000306}
307
308/*
309 * Destroys text converters
310 */
311 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100312mac_conv_cleanup(void)
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000313{
314 if (gUTF16ToUTF8Converter)
315 {
316 TECDisposeConverter(gUTF16ToUTF8Converter);
317 gUTF16ToUTF8Converter = NULL;
318 }
319
320 if (gPathConverter)
321 {
322 TECDisposeConverter(gPathConverter);
323 gPathConverter = NULL;
324 }
325}
326
327/*
328 * Conversion from UTF-16 UniChars to 'encoding'
Bram Moolenaar446cb832008-06-24 21:56:24 +0000329 * The function signature uses the real type of UniChar (as typedef'ed in
330 * CFBase.h) to avoid clashes with X11 header files in the .pro file
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000331 */
332 char_u *
Bram Moolenaar05540972016-01-30 20:31:25 +0100333mac_utf16_to_enc(
334 unsigned short *from,
335 size_t fromLen,
336 size_t *actualLen)
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000337{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100338 // Following code borrows somewhat from os_mswin.c
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000339 vimconv_T conv;
340 size_t utf8_len;
341 char_u *utf8_str;
342 char_u *result = NULL;
343
Bram Moolenaar0f873732019-12-05 20:28:46 +0100344 // Convert to utf-8 first, works better with iconv
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000345 utf8_len = 0;
346 utf8_str = mac_utf16_to_utf8(from, fromLen, &utf8_len);
347
348 if (utf8_str)
349 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100350 // We might be called before we have p_enc set up.
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000351 conv.vc_type = CONV_NONE;
352
Bram Moolenaar0f873732019-12-05 20:28:46 +0100353 // If encoding (p_enc) is any unicode, it is actually in utf-8 (vim
354 // internal unicode is always utf-8) so don't convert in such cases
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000355
356 if ((enc_canon_props(p_enc) & ENC_UNICODE) == 0)
357 convert_setup(&conv, (char_u *)"utf-8",
358 p_enc? p_enc: (char_u *)"macroman");
359 if (conv.vc_type == CONV_NONE)
360 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100361 // p_enc is utf-8, so we're done.
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000362 result = utf8_str;
363 }
364 else
365 {
366 result = string_convert(&conv, utf8_str, (int *)&utf8_len);
367 vim_free(utf8_str);
368 }
369
370 convert_setup(&conv, NULL, NULL);
371
372 if (actualLen)
373 *actualLen = utf8_len;
374 }
375 else if (actualLen)
376 *actualLen = 0;
377
378 return result;
379}
380
381/*
382 * Conversion from 'encoding' to UTF-16 UniChars
Bram Moolenaar446cb832008-06-24 21:56:24 +0000383 * The function return uses the real type of UniChar (as typedef'ed in
384 * CFBase.h) to avoid clashes with X11 header files in the .pro file
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000385 */
Bram Moolenaar446cb832008-06-24 21:56:24 +0000386 unsigned short *
Bram Moolenaar05540972016-01-30 20:31:25 +0100387mac_enc_to_utf16(
388 char_u *from,
389 size_t fromLen,
390 size_t *actualLen)
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000391{
Bram Moolenaar0f873732019-12-05 20:28:46 +0100392 // Following code borrows somewhat from os_mswin.c
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000393 vimconv_T conv;
394 size_t utf8_len;
395 char_u *utf8_str;
396 UniChar *result = NULL;
397 Boolean should_free_utf8 = FALSE;
398
399 do
400 {
Bram Moolenaar0f873732019-12-05 20:28:46 +0100401 // Use MacRoman by default, we might be called before we have p_enc
402 // set up. Convert to utf-8 first, works better with iconv(). Does
403 // nothing if 'encoding' is "utf-8".
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000404 conv.vc_type = CONV_NONE;
405 if ((enc_canon_props(p_enc) & ENC_UNICODE) == 0 &&
406 convert_setup(&conv, p_enc ? p_enc : (char_u *)"macroman",
407 (char_u *)"utf-8") == FAIL)
408 break;
409
410 if (conv.vc_type != CONV_NONE)
411 {
412 utf8_len = fromLen;
413 utf8_str = string_convert(&conv, from, (int *)&utf8_len);
414 should_free_utf8 = TRUE;
415 }
416 else
417 {
418 utf8_str = from;
419 utf8_len = fromLen;
420 }
421
422 if (utf8_str == NULL)
423 break;
424
425 convert_setup(&conv, NULL, NULL);
426
427 result = mac_utf8_to_utf16(utf8_str, utf8_len, actualLen);
428
429 if (should_free_utf8)
430 vim_free(utf8_str);
431 return result;
432 }
433 while (0);
434
435 if (actualLen)
436 *actualLen = 0;
437
438 return result;
439}
440
441/*
442 * Converts from UTF-16 UniChars to CFString
Bram Moolenaar446cb832008-06-24 21:56:24 +0000443 * The void * return type is actually a CFStringRef
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000444 */
Bram Moolenaar446cb832008-06-24 21:56:24 +0000445 void *
Bram Moolenaar05540972016-01-30 20:31:25 +0100446mac_enc_to_cfstring(
447 char_u *from,
448 size_t fromLen)
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000449{
450 UniChar *utf16_str;
451 size_t utf16_len;
452 CFStringRef result = NULL;
453
454 utf16_str = mac_enc_to_utf16(from, fromLen, &utf16_len);
455 if (utf16_str)
456 {
457 result = CFStringCreateWithCharacters(NULL, utf16_str, utf16_len/sizeof(UniChar));
458 vim_free(utf16_str);
459 }
460
Bram Moolenaar446cb832008-06-24 21:56:24 +0000461 return (void *)result;
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000462}
463
464/*
465 * Converts a decomposed HFS+ UTF-8 path to precomposed UTF-8
466 */
467 char_u *
Bram Moolenaar05540972016-01-30 20:31:25 +0100468mac_precompose_path(
469 char_u *decompPath,
470 size_t decompLen,
471 size_t *precompLen)
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000472{
473 char_u *result = NULL;
474 size_t actualLen = 0;
475
476 if (gPathConverter)
477 {
478 result = alloc(decompLen);
479 if (result)
480 {
481 if (TECConvertText(gPathConverter, decompPath,
482 decompLen, &decompLen, result,
483 decompLen, &actualLen) != noErr)
Bram Moolenaard23a8232018-02-10 18:45:26 +0100484 VIM_CLEAR(result);
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000485 }
486 }
487
488 if (precompLen)
489 *precompLen = actualLen;
490
491 return result;
492}
493
494/*
495 * Converts from UTF-16 UniChars to precomposed UTF-8
496 */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000497 static char_u *
Bram Moolenaar05540972016-01-30 20:31:25 +0100498mac_utf16_to_utf8(
499 UniChar *from,
500 size_t fromLen,
501 size_t *actualLen)
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000502{
503 ByteCount utf8_len;
504 ByteCount inputRead;
505 char_u *result;
506
507 if (gUTF16ToUTF8Converter)
508 {
509 result = alloc(fromLen * 6 + 1);
510 if (result && TECConvertText(gUTF16ToUTF8Converter, (ConstTextPtr)from,
511 fromLen, &inputRead, result,
512 (fromLen*6+1)*sizeof(char_u), &utf8_len) == noErr)
513 {
514 TECFlushText(gUTF16ToUTF8Converter, result, (fromLen*6+1)*sizeof(char_u), &inputRead);
515 utf8_len += inputRead;
516 }
517 else
Bram Moolenaard23a8232018-02-10 18:45:26 +0100518 VIM_CLEAR(result);
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000519 }
520 else
521 {
522 result = NULL;
523 }
524
525 if (actualLen)
526 *actualLen = result ? utf8_len : 0;
527
528 return result;
529}
530
531/*
532 * Converts from UTF-8 to UTF-16 UniChars
533 */
Bram Moolenaar7d47b6e2006-03-15 22:59:18 +0000534 static UniChar *
Bram Moolenaar05540972016-01-30 20:31:25 +0100535mac_utf8_to_utf16(
536 char_u *from,
537 size_t fromLen,
538 size_t *actualLen)
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000539{
540 CFStringRef utf8_str;
541 CFRange convertRange;
542 UniChar *result = NULL;
543
544 utf8_str = CFStringCreateWithBytes(NULL, from, fromLen,
545 kCFStringEncodingUTF8, FALSE);
546
Bram Moolenaarebfec1c2023-01-22 21:14:53 +0000547 if (utf8_str == NULL)
548 {
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000549 if (actualLen)
550 *actualLen = 0;
551 return NULL;
552 }
553
554 convertRange = CFRangeMake(0, CFStringGetLength(utf8_str));
Bram Moolenaarc799fe22019-05-28 23:08:19 +0200555 result = ALLOC_MULT(UniChar, convertRange.length);
Bram Moolenaar26a60b42005-02-22 08:49:11 +0000556
557 CFStringGetCharacters(utf8_str, convertRange, result);
558
559 CFRelease(utf8_str);
560
561 if (actualLen)
562 *actualLen = convertRange.length * sizeof(UniChar);
563
564 return result;
565}
Bram Moolenaar446cb832008-06-24 21:56:24 +0000566
567/*
568 * Sets LANG environment variable in Vim from Mac locale
569 */
570 void
Bram Moolenaar05540972016-01-30 20:31:25 +0100571mac_lang_init(void)
572{
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +0000573 if (mch_getenv((char_u *)"LANG") != NULL)
574 return;
Bram Moolenaara5fe91e2020-09-27 16:03:15 +0200575
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +0000576 char buf[50];
577
578 // $LANG is not set, either because it was unset or Vim was started
579 // from the Dock. Query the system locale.
580 if (LocaleRefGetPartString(NULL,
581 kLocaleLanguageMask | kLocaleLanguageVariantMask |
582 kLocaleRegionMask | kLocaleRegionVariantMask,
583 sizeof(buf) - 10, buf) == noErr && *buf)
584 {
585 if (strcasestr(buf, "utf-8") == NULL)
586 strcat(buf, ".UTF-8");
587 vim_setenv((char_u *)"LANG", (char_u *)buf);
Bram Moolenaar446cb832008-06-24 21:56:24 +0000588# ifdef HAVE_LOCALE_H
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +0000589 setlocale(LC_ALL, "");
Bram Moolenaar446cb832008-06-24 21:56:24 +0000590# endif
Bram Moolenaar73e28dc2022-09-17 21:08:33 +0100591# if defined(LC_NUMERIC)
Yegappan Lakshmanana41e2212023-01-16 18:19:05 +0000592 // Make sure strtod() uses a decimal point, not a comma.
593 setlocale(LC_NUMERIC, "C");
Bram Moolenaar509f8032020-09-24 23:08:19 +0200594# endif
Bram Moolenaar446cb832008-06-24 21:56:24 +0000595 }
596}
Bram Moolenaar0f873732019-12-05 20:28:46 +0100597#endif // MACOS_CONVERT