blob: 48023e3d3bb4506717894c234326a492a6a64a9c [file] [log] [blame]
/* 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 -- Mac specific things for Mac OS/X.
*/
#ifdef MACOS_X_UNIX
# ifdef HAVE_CONFIG_H /* Using Makefile. */
# include "vim.h"
# else
# include "os_unix.c" /* Using Project Builder */
# endif
#else
Error: MACOS 9 is no longer supported in Vim 7
#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},
{"iso-8859-15", kTextEncodingISOLatin9},
/* 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