diff options
Diffstat (limited to 'src/os_macosx.c')
-rw-r--r-- | src/os_macosx.c | 612 |
1 files changed, 612 insertions, 0 deletions
diff --git a/src/os_macosx.c b/src/os_macosx.c new file mode 100644 index 000000000..871eb7e5c --- /dev/null +++ b/src/os_macosx.c @@ -0,0 +1,612 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * os_macosx.c -- election of os_mac.c or os_unix.c + * + */ + +#ifdef MACOS_X_UNIX +# ifdef HAVE_CONFIG_H /* Using Makefile. */ +# include "vim.h" +# else +# include "os_unix.c" /* Using Project Builder */ +# endif +#else +# include "os_mac.c" +# include <TextEncodingConverter.h> +#endif + +#ifdef _DEBUG + void +Trace(char* fmt, ...) +{ + char buf[2048]; + va_list args; + + va_start(args, fmt); + /* vsnprintf(buf, sizeof(buf), fmt, args);*/ + fprintf(stderr, "%s", buf); + va_end(args); +} +#endif + +#ifdef MACOS_X_ICONVEMU +/* + * Libiconv emulation layer + */ + +struct _iconv_t +{ + TECObjectRef tec; + TECObjectRef tecReverse; + TECSnifferObjectRef sniff; + TextEncoding from; + TextEncoding to; +}; +/* typedef struct _iconv_t *iconv_t; */ + + +static int last_errno = 0; + +/* + * Get TextEncoding from iconv's encoding name + */ + static TextEncoding +get_textencoding(const char* encodename) +{ + static struct { + const char* name; + TextEncoding encode; + } encodetable[] = { + /* ISO-8859 encodings family */ + {"latin1", kTextEncodingISOLatin1}, + {"latin2", kTextEncodingISOLatin2}, + {"latin3", kTextEncodingISOLatin3}, + {"latin4", kTextEncodingISOLatin4}, + {"latin5", kTextEncodingISOLatin5}, + {"latin6", kTextEncodingISOLatin6}, + {"latin7", kTextEncodingISOLatin7}, + {"latin8", kTextEncodingISOLatin8}, + {"latin9", kTextEncodingISOLatin9}, + {"iso-8859-1", kTextEncodingISOLatin1}, + {"iso-8859-2", kTextEncodingISOLatin2}, + {"iso-8859-3", kTextEncodingISOLatin3}, + {"iso-8859-4", kTextEncodingISOLatin4}, + {"iso-8859-5", kTextEncodingISOLatinCyrillic}, + {"iso-8859-6", kTextEncodingISOLatinArabic}, + {"iso-8859-7", kTextEncodingISOLatinGreek}, + {"iso-8859-8", kTextEncodingISOLatinHebrew}, + {"iso-8859-9", kTextEncodingISOLatin5}, + {"iso-8859-10", kTextEncodingISOLatin6}, + + /* Unicode encodings. */ + /* TODO: Add other type of unicode */ + {"ucs-2", kTextEncodingMacUnicode}, + + /* Japanese encoding aliases */ + {"cp932", kTextEncodingShiftJIS}, + {"shift-jis", kTextEncodingShiftJIS}, + {"euc-jp", kTextEncodingEUC_JP}, + {"iso-2022-jp", kTextEncodingISO_2022_JP}, + {"iso-2022-jp-1", kTextEncodingISO_2022_JP_1}, + {"iso-2022-jp-2", kTextEncodingISO_2022_JP_2}, + {"iso-2022-jp-3", kTextEncodingISO_2022_JP_3}, + + /* Other aliases. These aliases in this block are just guessed. */ + /* TODO: Must be verified. */ + {"gb2312", kTextEncodingGB_2312_80}, + {"cp936", kTextEncodingMacChineseSimp}, + {"euc-cn", kTextEncodingEUC_CN}, + {"cp950", kTextEncodingMacChineseTrad}, + {"euc-tw", kTextEncodingEUC_TW}, + {"cp949", kTextEncodingMacKorean}, + {"euc-kr", kTextEncodingEUC_KR}, + + /* + * All encodings supported by Macintosh. You can find these values + * in a file: + * /System/Library/Frameworks/CoreServices.framework/Versions/A/ + * Frameworks/CarbonCore.framework/Versions/A/Headers/TextCommon.h + */ + {"MacRoman", kTextEncodingMacRoman}, + {"MacJapanese", kTextEncodingMacJapanese}, + {"MacChineseTrad", kTextEncodingMacChineseTrad}, + {"MacKorean", kTextEncodingMacKorean}, + {"MacArabic", kTextEncodingMacArabic}, + {"MacHebrew", kTextEncodingMacHebrew}, + {"MacGreek", kTextEncodingMacGreek}, + {"MacCyrillic", kTextEncodingMacCyrillic}, + {"MacDevanagari", kTextEncodingMacDevanagari}, + {"MacGurmukhi", kTextEncodingMacGurmukhi}, + {"MacGujarati", kTextEncodingMacGujarati}, + {"MacOriya", kTextEncodingMacOriya}, + {"MacBengali", kTextEncodingMacBengali}, + {"MacTamil", kTextEncodingMacTamil}, + {"MacTelugu", kTextEncodingMacTelugu}, + {"MacKannada", kTextEncodingMacKannada}, + {"MacMalayalam", kTextEncodingMacMalayalam}, + {"MacSinhalese", kTextEncodingMacSinhalese}, + {"MacBurmese", kTextEncodingMacBurmese}, + {"MacKhmer", kTextEncodingMacKhmer}, + {"MacThai", kTextEncodingMacThai}, + {"MacLaotian", kTextEncodingMacLaotian}, + {"MacGeorgian", kTextEncodingMacGeorgian}, + {"MacArmenian", kTextEncodingMacArmenian}, + {"MacChineseSimp", kTextEncodingMacChineseSimp}, + {"MacTibetan", kTextEncodingMacTibetan}, + {"MacMongolian", kTextEncodingMacMongolian}, + {"MacEthiopic", kTextEncodingMacEthiopic}, + {"MacCentralEurRoman", kTextEncodingMacCentralEurRoman}, + {"MacVietnamese", kTextEncodingMacVietnamese}, + {"MacExtArabic", kTextEncodingMacExtArabic}, + {"MacSymbol", kTextEncodingMacSymbol}, + {"MacDingbats", kTextEncodingMacDingbats}, + {"MacTurkish", kTextEncodingMacTurkish}, + {"MacCroatian", kTextEncodingMacCroatian}, + {"MacIcelandic", kTextEncodingMacIcelandic}, + {"MacRomanian", kTextEncodingMacRomanian}, + {"MacCeltic", kTextEncodingMacCeltic}, + {"MacGaelic", kTextEncodingMacGaelic}, + {"MacKeyboardGlyphs", kTextEncodingMacKeyboardGlyphs}, + {"MacTradChinese", kTextEncodingMacTradChinese}, + {"MacRSymbol", kTextEncodingMacRSymbol}, + {"MacSimpChinese", kTextEncodingMacSimpChinese}, + {"MacGeez", kTextEncodingMacGeez}, + {"MacEastEurRoman", kTextEncodingMacEastEurRoman}, + {"MacUninterp", kTextEncodingMacUninterp}, + {"MacUnicode", kTextEncodingMacUnicode}, + {"MacFarsi", kTextEncodingMacFarsi}, + {"MacUkrainian", kTextEncodingMacUkrainian}, + {"MacInuit", kTextEncodingMacInuit}, + {"MacVT100", kTextEncodingMacVT100}, + {"MacHFS", kTextEncodingMacHFS}, + {"UnicodeDefault", kTextEncodingUnicodeDefault}, + {"UnicodeV1_1", kTextEncodingUnicodeV1_1}, + {"ISO10646_1993", kTextEncodingISO10646_1993}, + {"UnicodeV2_0", kTextEncodingUnicodeV2_0}, + {"UnicodeV2_1", kTextEncodingUnicodeV2_1}, + {"UnicodeV3_0", kTextEncodingUnicodeV3_0}, + {"UnicodeV3_1", kTextEncodingUnicodeV3_1}, + {"UnicodeV3_2", kTextEncodingUnicodeV3_2}, + {"ISOLatin1", kTextEncodingISOLatin1}, + {"ISOLatin2", kTextEncodingISOLatin2}, + {"ISOLatin3", kTextEncodingISOLatin3}, + {"ISOLatin4", kTextEncodingISOLatin4}, + {"ISOLatinCyrillic", kTextEncodingISOLatinCyrillic}, + {"ISOLatinArabic", kTextEncodingISOLatinArabic}, + {"ISOLatinGreek", kTextEncodingISOLatinGreek}, + {"ISOLatinHebrew", kTextEncodingISOLatinHebrew}, + {"ISOLatin5", kTextEncodingISOLatin5}, + {"ISOLatin6", kTextEncodingISOLatin6}, + {"ISOLatin7", kTextEncodingISOLatin7}, + {"ISOLatin8", kTextEncodingISOLatin8}, + {"ISOLatin9", kTextEncodingISOLatin9}, + {"DOSLatinUS", kTextEncodingDOSLatinUS}, + {"DOSGreek", kTextEncodingDOSGreek}, + {"DOSBalticRim", kTextEncodingDOSBalticRim}, + {"DOSLatin1", kTextEncodingDOSLatin1}, + {"DOSGreek1", kTextEncodingDOSGreek1}, + {"DOSLatin2", kTextEncodingDOSLatin2}, + {"DOSCyrillic", kTextEncodingDOSCyrillic}, + {"DOSTurkish", kTextEncodingDOSTurkish}, + {"DOSPortuguese", kTextEncodingDOSPortuguese}, + {"DOSIcelandic", kTextEncodingDOSIcelandic}, + {"DOSHebrew", kTextEncodingDOSHebrew}, + {"DOSCanadianFrench", kTextEncodingDOSCanadianFrench}, + {"DOSArabic", kTextEncodingDOSArabic}, + {"DOSNordic", kTextEncodingDOSNordic}, + {"DOSRussian", kTextEncodingDOSRussian}, + {"DOSGreek2", kTextEncodingDOSGreek2}, + {"DOSThai", kTextEncodingDOSThai}, + {"DOSJapanese", kTextEncodingDOSJapanese}, + {"DOSChineseSimplif", kTextEncodingDOSChineseSimplif}, + {"DOSKorean", kTextEncodingDOSKorean}, + {"DOSChineseTrad", kTextEncodingDOSChineseTrad}, + {"WindowsLatin1", kTextEncodingWindowsLatin1}, + {"WindowsANSI", kTextEncodingWindowsANSI}, + {"WindowsLatin2", kTextEncodingWindowsLatin2}, + {"WindowsCyrillic", kTextEncodingWindowsCyrillic}, + {"WindowsGreek", kTextEncodingWindowsGreek}, + {"WindowsLatin5", kTextEncodingWindowsLatin5}, + {"WindowsHebrew", kTextEncodingWindowsHebrew}, + {"WindowsArabic", kTextEncodingWindowsArabic}, + {"WindowsBalticRim", kTextEncodingWindowsBalticRim}, + {"WindowsVietnamese", kTextEncodingWindowsVietnamese}, + {"WindowsKoreanJohab", kTextEncodingWindowsKoreanJohab}, + {"US_ASCII", kTextEncodingUS_ASCII}, + {"JIS_X0201_76", kTextEncodingJIS_X0201_76}, + {"JIS_X0208_83", kTextEncodingJIS_X0208_83}, + {"JIS_X0208_90", kTextEncodingJIS_X0208_90}, + {"JIS_X0212_90", kTextEncodingJIS_X0212_90}, + {"JIS_C6226_78", kTextEncodingJIS_C6226_78}, + {"ShiftJIS_X0213_00", kTextEncodingShiftJIS_X0213_00}, + {"GB_2312_80", kTextEncodingGB_2312_80}, + {"GBK_95", kTextEncodingGBK_95}, + {"GB_18030_2000", kTextEncodingGB_18030_2000}, + {"KSC_5601_87", kTextEncodingKSC_5601_87}, + {"KSC_5601_92_Johab", kTextEncodingKSC_5601_92_Johab}, + {"CNS_11643_92_P1", kTextEncodingCNS_11643_92_P1}, + {"CNS_11643_92_P2", kTextEncodingCNS_11643_92_P2}, + {"CNS_11643_92_P3", kTextEncodingCNS_11643_92_P3}, + {"ISO_2022_JP", kTextEncodingISO_2022_JP}, + {"ISO_2022_JP_2", kTextEncodingISO_2022_JP_2}, + {"ISO_2022_JP_1", kTextEncodingISO_2022_JP_1}, + {"ISO_2022_JP_3", kTextEncodingISO_2022_JP_3}, + {"ISO_2022_CN", kTextEncodingISO_2022_CN}, + {"ISO_2022_CN_EXT", kTextEncodingISO_2022_CN_EXT}, + {"ISO_2022_KR", kTextEncodingISO_2022_KR}, + {"EUC_JP", kTextEncodingEUC_JP}, + {"EUC_CN", kTextEncodingEUC_CN}, + {"EUC_TW", kTextEncodingEUC_TW}, + {"EUC_KR", kTextEncodingEUC_KR}, + {"ShiftJIS", kTextEncodingShiftJIS}, + {"KOI8_R", kTextEncodingKOI8_R}, + {"Big5", kTextEncodingBig5}, + {"MacRomanLatin1", kTextEncodingMacRomanLatin1}, + {"HZ_GB_2312", kTextEncodingHZ_GB_2312}, + {"Big5_HKSCS_1999", kTextEncodingBig5_HKSCS_1999}, + {"NextStepLatin", kTextEncodingNextStepLatin}, + {"EBCDIC_US", kTextEncodingEBCDIC_US}, + {"EBCDIC_CP037", kTextEncodingEBCDIC_CP037}, + {"MultiRun", kTextEncodingMultiRun}, + + /* Terminator */ + {NULL, -1}, + }; + int i; + + i = 0; + for (i = 0; encodetable[i].name != NULL; ++i) + { + if (STRICMP(encodename, encodetable[i].name) == 0) + break; + } + return encodetable[i].encode; +} + +/* + * iconv interfaces + */ + + iconv_t +iconv_open(const char* tocode, const char* fromcode) +{ + TextEncoding toEnc, fromEnc; + iconv_t cd = NULL; + OSStatus st; + + /* Verify to/from encoding name */ + toEnc = get_textencoding(tocode); + fromEnc = get_textencoding(fromcode); + if (toEnc < 0 || fromEnc < 0) + goto ICONV_OPEN_ERR; + + /* Allocate memory to object */ + cd = (iconv_t)alloc(sizeof(struct _iconv_t)); + if (!cd) + goto ICONV_OPEN_ERR; + memset(cd, 0, sizeof(struct _iconv_t)); + + /* Create converter */ + if (fromEnc != toEnc) + { + TRACE("*** fromEnc=%d toEnc=%d\n", (int)fromEnc, (int)toEnc); + st = TECCreateConverter(&cd->tec, fromEnc, toEnc); + if (st != 0) + { + TRACE("*** TECCreateConverter()=%d\n", (int)st); + goto ICONV_OPEN_ERR; + } + /* Create reverse converter */ + st = TECCreateConverter(&cd->tecReverse, toEnc, fromEnc); + if (st != 0) + { + TRACE("*** TECCreateConverter()=%d (reverse)\n", (int)st); + goto ICONV_OPEN_ERR; + } + /* Create Sniffer */ + st = TECCreateSniffer(&cd->sniff, &fromEnc, 1); + if (st != 0) + { + TRACE("*** TECCreateSniffer()=%d\n", (int)st); + goto ICONV_OPEN_ERR; + } + } + + cd->from = fromEnc; + cd->to = toEnc; + last_errno = 0; + return cd; + +ICONV_OPEN_ERR: + if (cd) + iconv_close(cd); + last_errno = EINVAL; + return (iconv_t)-1; +} + +/* + * Used when there are same value in 'from encoding' and 'to encoding'. + * TEC doesn't support conversion between same encodings, and + * TECCreateConverter() failed. + */ + static size_t +null_conv(iconv_t cd, const char** inbuf, size_t *inbytesleft, + char** outbuf, size_t *outbytesleft) +{ + const char* buf_in = inbuf && *inbuf ? *inbuf : NULL; + char* buf_out = outbuf && *outbuf ? *outbuf : NULL; + + if (buf_in) + { + int in_len = inbytesleft ? *inbytesleft : 0; + int out_len = outbytesleft ? *outbytesleft : 0; + + if (!buf_out || out_len <= 0) + { + last_errno = E2BIG; + return -1; + } + else if (in_len > 0) + { + int len = in_len < out_len ? in_len : out_len; + + memcpy (buf_out, buf_in, len); + *inbuf += len; + *outbuf += len; + *inbytesleft -= len; + *outbytesleft -= len; + if (*outbytesleft <= 0) + { + last_errno = E2BIG; + return -1; + } + } + } + last_errno = 0; + return 0; +} + + size_t +iconv(iconv_t cd, const char** inbuf, size_t *inbytesleft, + char** outbuf, size_t *outbytesleft) +{ + ConstTextPtr buf_in; + TextPtr buf_out; + ByteCount out_len, out_true; + ByteCount in_len, in_true; + OSStatus st; + + if (!cd) + { + last_errno = ENOENT; /* TODO: Another error code should be set */ + return -1; + } + if (cd->from == cd->to) + return null_conv(cd, inbuf, inbytesleft, outbuf, outbytesleft) ; + + buf_in = (TextPtr) inbuf ; + buf_out = (TextPtr) outbuf ; + out_len = out_true = -1; + in_len = in_true = -1; + + if (buf_in && buf_out) + { + ItemCount error, feature; + + /* Normal convert mode */ + if (!inbytesleft || !outbytesleft) + { + last_errno = EFAULT; + return -1; + } + in_len = *inbytesleft; + out_len = *outbytesleft; + + /* Check stream is form in expected encoding or not */ + st = TECSniffTextEncoding(cd->sniff, (TextPtr)buf_in, in_len, + &cd->from, 1, &error, 1, &feature, 1); + TRACE("TECSniffTextEncoding()=%d error=%d feature=%d\n", + (int)st, (int)error, (int)feature); + if ((error != 0 || feature == 0) + && !(error == 0xffffffff && feature == 0xffffffff)) + /* Not expected encoding */ + st = kTECUnmappableElementErr; + else + { + /* Do convert */ + st = TECConvertText(cd->tec, + buf_in, in_len, &in_true, + buf_out, out_len, &out_true); + /* Verify converted text. Compare original text with reverse + * converted text. If not match, there is some problem on + * converting. */ + if (st == 0 && in_true > 0) + { + ByteCount rev_in, rev_out; + TextPtr buf_rev = (TextPtr)alloc(in_true); + + if (buf_rev) + { + st = TECConvertText(cd->tecReverse, + buf_out, out_true, &rev_in, + buf_rev, in_true, &rev_out); + if (st != 0 || rev_in != out_true || rev_out != in_true + || memcmp(buf_rev, buf_in, rev_out) != 0) + { +#ifdef ICONVOSX_DEBUG + fprintf(stderr, " reverse conversion failed.\n"); +#endif + st = kTECUnmappableElementErr; + } + vim_free(buf_rev); + } + else + st = kTECUnmappableElementErr; + } + } + } + else if (!buf_in && buf_out) + { + /* Flush all buffered strings to buffer, and reset status */ + if (!outbytesleft) + { + last_errno = EFAULT; + return -1; + } + out_len = *outbytesleft; + st = TECFlushText(cd->tec, + buf_out, out_len, &out_true); + } + else if (!buf_in && !buf_out) + { + /* Reset cd's status and cancel buffered strings */ + unsigned char tmp_out[256]; + + buf_out = tmp_out; + out_len = sizeof(tmp_out); + st = TECFlushText(cd->tec, + buf_out, out_len, &out_true); + } + else + { + last_errno = EFAULT; + return -1; + } + TRACE("st=%d, buf_in=%p, in_len=%d, in_true=%d\n" + " buf_out=%p, out_len=%d, out_true=%d\n", (int)st, + buf_in, (int)in_len, (int)in_true, + buf_out, (int)out_len, (int)out_true); + + switch (st) + { + case 0: + /* No error */ + if (inbytesleft) + *inbytesleft -= in_true; + if (outbytesleft) + *outbytesleft -= out_true; + if (inbuf && *inbuf) + *inbuf += in_true; + if (outbuf && *outbuf) + *outbuf += out_true; + last_errno = 0; + return 0; /* No error */ + case kTECUnmappableElementErr: + last_errno = EILSEQ; + case kTECIncompleteElementErr: + last_errno = EINVAL; + case kTECOutputBufferFullStatus: + last_errno = E2BIG; + return -1; + default: + TRACE("iconv(%p, %p, %p, %p, %p) failed. (%d)\n", + cd, inbuf, inbytesleft, outbuf, outbytesleft, (int)st); + last_errno = EFAULT; + return -1; + } +} + + int +iconv_close(iconv_t cd) +{ + if (cd) + { + /* Free all elements of iconv_t */ + if (cd->tec) + TECDisposeConverter(cd->tec); + if (cd->tecReverse) + TECDisposeConverter(cd->tecReverse); + if (cd->sniff) + TECDisposeSniffer(cd->sniff); + vim_free(cd); + last_errno = 0; + return 0; + } + else + { + last_errno = EINVAL; + return -1; + } +} + + int* +iconv_errno() +{ + return &last_errno; +} +#endif /* MACOS_X_ICONVEMU */ + +#ifdef USE_MCH_GETTEXT + +#define GETTEXT_BUFNUM 64 +#define GETTEXT_BUFSIZE 256 + + char* +mch_gettext(const char* msgid) +{ + static char buf[GETTEXT_BUFNUM][GETTEXT_BUFSIZE]; + static int bufnum = 0; + const char *msg = NULL; + CFStringRef strkey = NULL, strmsg = NULL; + CFStringEncoding enc; + + if (!msgid) + goto MCH_GETTEXT_FINISH; + enc = CFStringGetSystemEncoding(); + TRACE("mch_gettext(%s)\n", msgid); + + strkey = CFStringCreateWithCString(NULL, msgid, enc); + if (!strkey) + { + TRACE(" Can't create a CFString for msgid.\n"); + goto MCH_GETTEXT_FINISH; + } + + strmsg = CFCopyLocalizedString(strkey, NULL); + if (!strmsg) + { + TRACE(" No localized strings for msgid.\n"); + goto MCH_GETTEXT_FINISH; + } + + msg = CFStringGetCStringPtr(strmsg, enc); + if (!msg) + { + /* This is as backup when CFStringGetCStringPtr was failed */ + CFStringGetCString(strmsg, buf[bufnum], GETTEXT_BUFSIZE, enc); + msg = buf[bufnum]; + if (++bufnum >= GETTEXT_BUFNUM) + bufnum = 0; + } + TRACE(" Localized to: %s\n", msg); + +MCH_GETTEXT_FINISH: + if (strkey) + CFRelease(strkey); + if (strmsg) + CFRelease(strmsg); + return (char*)(msg ? msg : msgid); +} + + char* +mch_bindtextdomain(const char* domain, const char* dirname) +{ + TRACE("mch_bindtextdomain(%s, %s)\n", domain, dirname); + return (char*)dirname; +} + + char* +mch_textdomain(const char* domain) +{ + TRACE("mch_textdomain(%s)\n", domain); + return (char*)domain; +} +#endif |