home *** CD-ROM | disk | FTP | other *** search
/ vim.ftp.fu-berlin.de / 2015-02-03.vim.ftp.fu-berlin.de.tar / vim.ftp.fu-berlin.de / unix / vim-6.2.tar.bz2 / vim-6.2.tar / vim62 / src / mbyte.c < prev    next >
Encoding:
C/C++ Source or Header  |  2003-05-31  |  132.1 KB  |  5,217 lines

  1. /* vi:set ts=8 sts=4 sw=4:
  2.  *
  3.  * VIM - Vi IMproved    by Bram Moolenaar
  4.  * Multibyte extensions partly by Sung-Hoon Baek
  5.  *
  6.  * Do ":help uganda"  in Vim to read copying and usage conditions.
  7.  * Do ":help credits" in Vim to see a list of people who contributed.
  8.  * See README.txt for an overview of the Vim source code.
  9.  */
  10. /*
  11.  * mbyte.c: Code specifically for handling multi-byte characters.
  12.  *
  13.  * The encoding used in the core is set with 'encoding'.  When 'encoding' is
  14.  * changed, the following four variables are set (for speed).
  15.  * Currently these types of character encodings are supported:
  16.  *
  17.  * "enc_dbcs"        When non-zero it tells the type of double byte character
  18.  *            encoding (Chinese, Korean, Japanese, etc.).
  19.  *            The cell width on the display is equal to the number of
  20.  *            bytes.  (exception: DBCS_JPNU with first byte 0x8e)
  21.  *            Recognizing the first or second byte is difficult, it
  22.  *            requires checking a byte sequence from the start.
  23.  * "enc_utf8"        When TRUE use Unicode characters in UTF-8 encoding.
  24.  *            The cell width on the display needs to be determined from
  25.  *            the character value.
  26.  *            Recognizing bytes is easy: 0xxx.xxxx is a single-byte
  27.  *            char, 10xx.xxxx is a trailing byte, 11xx.xxxx is a leading
  28.  *            byte of a multi-byte character.
  29.  *            To make things complicated, up to two composing characters
  30.  *            are allowed.  These are drawn on top of the first char.
  31.  *            For most editing the sequence of bytes with composing
  32.  *            characters included is considered to be one character.
  33.  * "enc_unicode"    When 2 use 16-bit Unicode characters (or UTF-16).
  34.  *            When 4 use 32-but Unicode characters.
  35.  *            Internally characters are stored in UTF-8 encoding to
  36.  *            avoid NUL bytes.  Conversion happens when doing I/O.
  37.  *            "enc_utf8" will also be TRUE.
  38.  *
  39.  * "has_mbyte" is set when "enc_dbcs" or "enc_utf8" is non-zero.
  40.  *
  41.  * If none of these is TRUE, 8-bit bytes are used for a character.  The
  42.  * encoding isn't currently specified (TODO).
  43.  *
  44.  * 'encoding' specifies the encoding used in the core.  This is in registers,
  45.  * text manipulation, buffers, etc.  Conversion has to be done when characters
  46.  * in another encoding are received or send:
  47.  *
  48.  *               clipboard
  49.  *               ^
  50.  *               | (2)
  51.  *               V
  52.  *           +---------------+
  53.  *          (1)  |           | (3)
  54.  *  keyboard ----->|     core       |-----> display
  55.  *           |           |
  56.  *           +---------------+
  57.  *               ^
  58.  *               | (4)
  59.  *               V
  60.  *             file
  61.  *
  62.  * (1) Typed characters arrive in the current locale.  Conversion is to be
  63.  *     done when 'encoding' is different from 'termencoding'.
  64.  * (2) Text will be made available with the encoding specified with
  65.  *     'encoding'.  If this is not sufficient, system-specific conversion
  66.  *     might be required.
  67.  * (3) For the GUI the correct font must be selected, no conversion done.
  68.  *     Otherwise, conversion is to be done when 'encoding' differs from
  69.  *     'termencoding'.  (Different in the GTK+ 2 port -- 'termencoding'
  70.  *     is always used for both input and output and must always be set to
  71.  *     "utf-8".  gui_mch_init() does this automatically.)
  72.  * (4) The encoding of the file is specified with 'fileencoding'.  Conversion
  73.  *     is to be done when it's different from 'encoding'.
  74.  *
  75.  * The viminfo file is a special case: Only text is converted, not file names.
  76.  * Vim scripts may contain an ":encoding" command.  This has an effect for
  77.  * some commands, like ":menutrans"
  78.  */
  79.  
  80. #include "vim.h"
  81.  
  82. #ifdef WIN32UNIX
  83. # ifndef WIN32_LEAN_AND_MEAN
  84. #  define WIN32_LEAN_AND_MEAN
  85. # endif
  86. # include <windows.h>
  87. # ifdef WIN32
  88. #  undef WIN32        /* Some windows.h define WIN32, we don't want that here. */
  89. # endif
  90. #endif
  91.  
  92. #if (defined(WIN3264) || defined(WIN32UNIX)) && !defined(__MINGW32__)
  93. # include <winnls.h>
  94. #endif
  95.  
  96. #ifdef FEAT_GUI_X11
  97. # include <X11/Intrinsic.h>
  98. #endif
  99. #ifdef X_LOCALE
  100. #include <X11/Xlocale.h>
  101. #endif
  102.  
  103. #if defined(FEAT_XIM) && defined(HAVE_GTK2)
  104. # include <gdk/gdkkeysyms.h>
  105. # include <gdk/gdkx.h>
  106. #endif
  107.  
  108. #if defined(FEAT_MBYTE) || defined(PROTO)
  109.  
  110. static int enc_canon_search __ARGS((char_u *name));
  111. static int dbcs_char2len __ARGS((int c));
  112. static int dbcs_char2bytes __ARGS((int c, char_u *buf));
  113. static int dbcs_ptr2len_check __ARGS((char_u *p));
  114. static int dbcs_char2cells __ARGS((int c));
  115. static int dbcs_ptr2char __ARGS((char_u *p));
  116.  
  117. /* Lookup table to quickly get the length in bytes of a UTF-8 character from
  118.  * the first byte of a UTF-8 string.  Bytes which are illegal when used as the
  119.  * first byte have a one, because these will be used separately. */
  120. static char utf8len_tab[256] =
  121. {
  122.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  123.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  124.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  125.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
  126.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /*bogus*/
  127.     1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /*bogus*/
  128.     2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
  129.     3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,6,6,1,1,
  130. };
  131.  
  132. #endif
  133.  
  134. #if defined(FEAT_MBYTE) || defined(FEAT_POSTSCRIPT) || defined(PROTO)
  135. /*
  136.  * Canonical encoding names and their properties.
  137.  * "iso-8859-n" is handled by enc_canonize() directly.
  138.  */
  139. static struct
  140. {   char *name;        int prop;        int codepage;}
  141. enc_canon_table[] =
  142. {
  143. #define IDX_LATIN_1    0
  144.     {"latin1",        ENC_8BIT + ENC_LATIN1,    1252},
  145. #define IDX_ISO_2    1
  146.     {"iso-8859-2",    ENC_8BIT,        0},
  147. #define IDX_ISO_3    2
  148.     {"iso-8859-3",    ENC_8BIT,        0},
  149. #define IDX_ISO_4    3
  150.     {"iso-8859-4",    ENC_8BIT,        0},
  151. #define IDX_ISO_5    4
  152.     {"iso-8859-5",    ENC_8BIT,        0},
  153. #define IDX_ISO_6    5
  154.     {"iso-8859-6",    ENC_8BIT,        0},
  155. #define IDX_ISO_7    6
  156.     {"iso-8859-7",    ENC_8BIT,        0},
  157. #define IDX_CP1255    7
  158.     {"cp1255",        ENC_8BIT,        1255}, /* close to iso-8859-8 */
  159. #define IDX_ISO_8    8
  160.     {"iso-8859-8",    ENC_8BIT,        0},
  161. #define IDX_ISO_9    9
  162.     {"iso-8859-9",    ENC_8BIT,        0},
  163. #define IDX_ISO_10    10
  164.     {"iso-8859-10",    ENC_8BIT,        0},
  165. #define IDX_ISO_11    11
  166.     {"iso-8859-11",    ENC_8BIT,        0},
  167. #define IDX_ISO_13    12
  168.     {"iso-8859-13",    ENC_8BIT,        0},
  169. #define IDX_ISO_14    13
  170.     {"iso-8859-14",    ENC_8BIT,        0},
  171. #define IDX_ISO_15    14
  172.     {"iso-8859-15",    ENC_8BIT,        0},
  173. #define IDX_KOI8_R    15
  174.     {"koi8-r",        ENC_8BIT,        0},
  175. #define IDX_KOI8_U    16
  176.     {"koi8-u",        ENC_8BIT,        0},
  177. #define IDX_UTF8    17
  178.     {"utf-8",        ENC_UNICODE,        0},
  179. #define IDX_UCS2    18
  180.     {"ucs-2",        ENC_UNICODE + ENC_ENDIAN_B + ENC_2BYTE, 0},
  181. #define IDX_UCS2LE    19
  182.     {"ucs-2le",        ENC_UNICODE + ENC_ENDIAN_L + ENC_2BYTE, 0},
  183. #define IDX_UTF16    20
  184.     {"utf-16",        ENC_UNICODE + ENC_ENDIAN_B + ENC_2WORD, 0},
  185. #define IDX_UTF16LE    21
  186.     {"utf-16le",    ENC_UNICODE + ENC_ENDIAN_L + ENC_2WORD, 0},
  187. #define IDX_UCS4    22
  188.     {"ucs-4",        ENC_UNICODE + ENC_ENDIAN_B + ENC_4BYTE, 0},
  189. #define IDX_UCS4LE    23
  190.     {"ucs-4le",        ENC_UNICODE + ENC_ENDIAN_L + ENC_4BYTE, 0},
  191. #define IDX_DEBUG    24
  192.     {"debug",        ENC_DBCS,        DBCS_DEBUG},
  193. #define IDX_CP932    25
  194.     {"cp932",        ENC_DBCS,        DBCS_JPN},
  195. #define IDX_CP949    26
  196.     {"cp949",        ENC_DBCS,        DBCS_KOR},
  197. #define IDX_CP936    27
  198.     {"cp936",        ENC_DBCS,        DBCS_CHS},
  199. #define IDX_CP950    28
  200.     {"cp950",        ENC_DBCS,        DBCS_CHT},
  201. #define IDX_EUC_JP    29
  202.     {"euc-jp",        ENC_DBCS,        DBCS_JPNU},
  203. #define IDX_SJIS    30
  204.     {"sjis",        ENC_DBCS,        DBCS_JPN},
  205. #define IDX_EUC_KR    31
  206.     {"euc-kr",        ENC_DBCS,        DBCS_KORU},
  207. #define IDX_EUC_CN    32
  208.     {"euc-cn",        ENC_DBCS,        DBCS_CHSU},
  209. #define IDX_EUC_TW    33
  210.     {"euc-tw",        ENC_DBCS,        DBCS_CHTU},
  211. #define IDX_BIG5    34
  212.     {"big5",        ENC_DBCS,        DBCS_CHT},
  213. #define IDX_COUNT    35
  214. };
  215.  
  216. /*
  217.  * Aliases for encoding names.
  218.  */
  219. static struct
  220. {   char *name;        int canon;}
  221. enc_alias_table[] =
  222. {
  223.     {"ansi",        IDX_LATIN_1},
  224.     {"iso-8859-1",    IDX_LATIN_1},
  225.     {"latin2",        IDX_ISO_2},
  226.     {"latin3",        IDX_ISO_3},
  227.     {"latin4",        IDX_ISO_4},
  228.     {"cyrillic",    IDX_ISO_5},
  229.     {"arabic",        IDX_ISO_6},
  230.     {"greek",        IDX_ISO_7},
  231. #ifdef WIN3264
  232.     {"hebrew",        IDX_CP1255},
  233. #else
  234.     {"hebrew",        IDX_ISO_8},
  235. #endif
  236.     {"latin5",        IDX_ISO_9},
  237.     {"turkish",        IDX_ISO_9}, /* ? */
  238.     {"latin6",        IDX_ISO_10},
  239.     {"nordic",        IDX_ISO_10}, /* ? */
  240.     {"thai",        IDX_ISO_11}, /* ? */
  241.     {"latin7",        IDX_ISO_13},
  242.     {"latin8",        IDX_ISO_14},
  243.     {"latin9",        IDX_ISO_15},
  244.     {"utf8",        IDX_UTF8},
  245.     {"unicode",        IDX_UCS2},
  246.     {"ucs2",        IDX_UCS2},
  247.     {"ucs2be",        IDX_UCS2},
  248.     {"ucs-2be",        IDX_UCS2},
  249.     {"ucs2le",        IDX_UCS2LE},
  250.     {"utf16",        IDX_UTF16},
  251.     {"utf16be",        IDX_UTF16},
  252.     {"utf-16be",    IDX_UTF16},
  253.     {"utf16le",        IDX_UTF16LE},
  254.     {"ucs4",        IDX_UCS4},
  255.     {"ucs4be",        IDX_UCS4},
  256.     {"ucs-4be",        IDX_UCS4},
  257.     {"ucs4le",        IDX_UCS4LE},
  258.     {"932",        IDX_CP932},
  259.     {"949",        IDX_CP949},
  260.     {"936",        IDX_CP936},
  261.     {"950",        IDX_CP950},
  262.     {"eucjp",        IDX_EUC_JP},
  263.     {"unix-jis",    IDX_EUC_JP},
  264.     {"ujis",        IDX_EUC_JP},
  265.     {"shift-jis",    IDX_SJIS},
  266.     {"euckr",        IDX_EUC_KR},
  267.     {"5601",        IDX_EUC_KR},    /* Sun: KS C 5601 */
  268.     {"euccn",        IDX_EUC_CN},
  269.     {"gb2312",        IDX_EUC_CN},
  270.     {"euctw",        IDX_EUC_TW},
  271. #if defined(WIN3264) || defined(WIN32UNIX) || defined(MACOS)
  272.     {"japan",        IDX_CP932},
  273.     {"korea",        IDX_CP949},
  274.     {"prc",        IDX_CP936},
  275.     {"chinese",        IDX_CP936},
  276.     {"taiwan",        IDX_CP950},
  277.     {"big5",        IDX_CP950},
  278. #else
  279.     {"japan",        IDX_EUC_JP},
  280.     {"korea",        IDX_EUC_KR},
  281.     {"prc",        IDX_EUC_CN},
  282.     {"chinese",        IDX_EUC_CN},
  283.     {"taiwan",        IDX_EUC_TW},
  284.     {"cp950",        IDX_BIG5},
  285.     {"950",        IDX_BIG5},
  286. #endif
  287.     {NULL,        0}
  288. };
  289.  
  290. #ifndef CP_UTF8
  291. # define CP_UTF8 65001    /* magic number from winnls.h */
  292. #endif
  293.  
  294. /*
  295.  * Find encoding "name" in the list of canonical encoding names.
  296.  * Returns -1 if not found.
  297.  */
  298.     static int
  299. enc_canon_search(name)
  300.     char_u    *name;
  301. {
  302.     int        i;
  303.  
  304.     for (i = 0; i < IDX_COUNT; ++i)
  305.     if (STRCMP(name, enc_canon_table[i].name) == 0)
  306.         return i;
  307.     return -1;
  308. }
  309.  
  310. #endif
  311.  
  312. #if defined(FEAT_MBYTE) || defined(PROTO)
  313.  
  314. /*
  315.  * Find canonical encoding "name" in the list and return its properties.
  316.  * Returns 0 if not found.
  317.  */
  318.     int
  319. enc_canon_props(name)
  320.     char_u    *name;
  321. {
  322.     int        i;
  323.  
  324.     i = enc_canon_search(name);
  325.     if (i >= 0)
  326.     return enc_canon_table[i].prop;
  327. #ifdef WIN3264
  328.     if (name[0] == 'c' && name[1] == 'p' && isdigit(name[2]))
  329.     {
  330.     CPINFO    cpinfo;
  331.  
  332.     /* Get info on this codepage to find out what it is. */
  333.     if (GetCPInfo(atoi(name + 2), &cpinfo) != 0)
  334.     {
  335.         if (cpinfo.MaxCharSize == 1) /* some single-byte encoding */
  336.         return ENC_8BIT;
  337.         if (cpinfo.MaxCharSize == 2
  338.             && (cpinfo.LeadByte[0] != 0 || cpinfo.LeadByte[1] != 0))
  339.         /* must be a DBCS encoding */
  340.         return ENC_DBCS;
  341.     }
  342.     return 0;
  343.     }
  344. #endif
  345.     if (STRNCMP(name, "2byte-", 6) == 0)
  346.     return ENC_DBCS;
  347.     if (STRNCMP(name, "8bit-", 5) == 0 || STRNCMP(name, "iso-8859-", 9) == 0)
  348.     return ENC_8BIT;
  349.     return 0;
  350. }
  351.  
  352. /*
  353.  * Set up for using multi-byte characters.
  354.  * Called in three cases:
  355.  * - by main() to initialize (p_enc == NULL)
  356.  * - by set_init_1() after 'encoding' was set to its default.
  357.  * - by do_set() when 'encoding' has been set.
  358.  * p_enc must have been passed through enc_canonize() already.
  359.  * Sets the "enc_unicode", "enc_utf8", "enc_dbcs" and "has_mbyte" flags.
  360.  * Fills mb_bytelen_tab[] and returns NULL when there are no problems.
  361.  * When there is something wrong: Returns an error message and doesn't change
  362.  * anything.
  363.  */
  364.     char_u *
  365. mb_init()
  366. {
  367.     int        i;
  368.     int        idx;
  369.     int        n;
  370.     int        enc_dbcs_new = 0;
  371.  
  372.     if (p_enc == NULL)
  373.     {
  374.     /* Just starting up: set the whole table to one's. */
  375.     for (i = 0; i < 256; ++i)
  376.         mb_bytelen_tab[i] = 1;
  377.     input_conv.vc_type = CONV_NONE;
  378.     input_conv.vc_factor = 1;
  379.     output_conv.vc_type = CONV_NONE;
  380.     return NULL;
  381.     }
  382.  
  383. #ifdef WIN3264
  384.     if (p_enc[0] == 'c' && p_enc[1] == 'p' && isdigit(p_enc[2]))
  385.     {
  386.     CPINFO    cpinfo;
  387.  
  388.     /* Get info on this codepage to find out what it is. */
  389.     if (GetCPInfo(atoi(p_enc + 2), &cpinfo) != 0)
  390.     {
  391.         if (cpinfo.MaxCharSize == 1)
  392.         {
  393.         /* some single-byte encoding */
  394.         enc_unicode = 0;
  395.         enc_utf8 = FALSE;
  396.         }
  397.         else if (cpinfo.MaxCharSize == 2
  398.             && (cpinfo.LeadByte[0] != 0 || cpinfo.LeadByte[1] != 0))
  399.         {
  400.         /* must be a DBCS encoding, check below */
  401.         enc_dbcs_new = atoi(p_enc + 2);
  402.         }
  403.         else
  404.         goto codepage_invalid;
  405.     }
  406.     else if (GetLastError() == ERROR_INVALID_PARAMETER)
  407.     {
  408. codepage_invalid:
  409.         return (char_u *)N_("E543: Not a valid codepage");
  410.     }
  411.     }
  412. #endif
  413.     else if (STRNCMP(p_enc, "8bit-", 5) == 0
  414.         || STRNCMP(p_enc, "iso-8859-", 9) == 0)
  415.     {
  416.     /* Accept any "8bit-" or "iso-8859-" name. */
  417.     enc_unicode = 0;
  418.     enc_utf8 = FALSE;
  419.     }
  420.     else if (STRNCMP(p_enc, "2byte-", 6) == 0)
  421.     {
  422. #ifdef WIN3264
  423.     /* Windows: accept only valid codepage numbers, check below. */
  424.     if (p_enc[6] != 'c' || p_enc[7] != 'p'
  425.                       || (enc_dbcs_new = atoi(p_enc + 8)) == 0)
  426.         return e_invarg;
  427. #else
  428.     /* Unix: accept any "2byte-" name, assume current locale. */
  429.     enc_dbcs_new = DBCS_2BYTE;
  430. #endif
  431.     }
  432.     else if ((idx = enc_canon_search(p_enc)) >= 0)
  433.     {
  434.     i = enc_canon_table[idx].prop;
  435.     if (i & ENC_UNICODE)
  436.     {
  437.         /* Unicode */
  438.         enc_utf8 = TRUE;
  439.         if (i & (ENC_2BYTE | ENC_2WORD))
  440.         enc_unicode = 2;
  441.         else if (i & ENC_4BYTE)
  442.         enc_unicode = 4;
  443.         else
  444.         enc_unicode = 0;
  445.     }
  446.     else if (i & ENC_DBCS)
  447.     {
  448.         /* 2byte, handle below */
  449.         enc_dbcs_new = enc_canon_table[idx].codepage;
  450.     }
  451.     else
  452.     {
  453.         /* Must be 8-bit. */
  454.         enc_unicode = 0;
  455.         enc_utf8 = FALSE;
  456.     }
  457.     }
  458.     else    /* Don't know what encoding this is, reject it. */
  459.     return e_invarg;
  460.  
  461.     if (enc_dbcs_new != 0)
  462.     {
  463. #ifdef WIN3264
  464.     /* Check if the DBCS code page is OK. */
  465.     if (!IsValidCodePage(enc_dbcs_new))
  466.         goto codepage_invalid;
  467. #endif
  468.     enc_unicode = 0;
  469.     enc_utf8 = FALSE;
  470.     }
  471.     enc_dbcs = enc_dbcs_new;
  472.     has_mbyte = (enc_dbcs != 0 || enc_utf8);
  473.  
  474. #ifdef WIN3264
  475.     enc_codepage = encname2codepage(p_enc);
  476. #endif
  477.  
  478.     /*
  479.      * Set the function pointers.
  480.      */
  481.     if (enc_utf8)
  482.     {
  483.     mb_ptr2len_check = utfc_ptr2len_check;
  484.     mb_char2len = utf_char2len;
  485.     mb_char2bytes = utf_char2bytes;
  486.     mb_ptr2cells = utf_ptr2cells;
  487.     mb_char2cells = utf_char2cells;
  488.     mb_off2cells = utf_off2cells;
  489.     mb_ptr2char = utf_ptr2char;
  490.     mb_head_off = utf_head_off;
  491.     }
  492.     else if (enc_dbcs != 0)
  493.     {
  494.     mb_ptr2len_check = dbcs_ptr2len_check;
  495.     mb_char2len = dbcs_char2len;
  496.     mb_char2bytes = dbcs_char2bytes;
  497.     mb_ptr2cells = dbcs_ptr2cells;
  498.     mb_char2cells = dbcs_char2cells;
  499.     mb_off2cells = dbcs_off2cells;
  500.     mb_ptr2char = dbcs_ptr2char;
  501.     mb_head_off = dbcs_head_off;
  502.     }
  503.     else
  504.     {
  505.     mb_ptr2len_check = latin_ptr2len_check;
  506.     mb_char2len = latin_char2len;
  507.     mb_char2bytes = latin_char2bytes;
  508.     mb_ptr2cells = latin_ptr2cells;
  509.     mb_char2cells = latin_char2cells;
  510.     mb_off2cells = latin_off2cells;
  511.     mb_ptr2char = latin_ptr2char;
  512.     mb_head_off = latin_head_off;
  513.     }
  514.  
  515.     /*
  516.      * Fill the mb_bytelen_tab[] for MB_BYTE2LEN().
  517.      */
  518.     for (i = 0; i < 256; ++i)
  519.     {
  520.     /* Our own function to reliably check the lenght of UTF-8 characters,
  521.      * independent of mblen(). */
  522.     if (enc_utf8)
  523.         n = utf8len_tab[i];
  524.     else if (enc_dbcs == 0)
  525.         n = 1;
  526.     else
  527.     {
  528. #if defined(WIN3264) || defined(WIN32UNIX)
  529.         /* enc_dbcs is set by setting 'fileencoding'.  It becomes a Windows
  530.          * CodePage identifier, which we can pass directly in to Windows
  531.          * API */
  532.         n = IsDBCSLeadByteEx(enc_dbcs, (BYTE)i) ? 2 : 1;
  533. #else
  534. # ifdef MACOS
  535.         /*
  536.          * if mblen() is not available, character which MSB is turned on
  537.          * are treated as leading byte character. (note : This assumption
  538.          * is not always true.)
  539.          */
  540.         n = (i & 0x80) ? 2 : 1;
  541. # else
  542.         char buf[MB_MAXBYTES];
  543. # ifdef X_LOCALE
  544.         extern int _Xmblen __ARGS((char *, size_t));
  545. #  ifndef mblen
  546. #   define mblen _Xmblen
  547. #  endif
  548. # endif
  549.         if (i == NUL)    /* just in case mblen() can't handle "" */
  550.         n = 1;
  551.         else
  552.         {
  553.         /*
  554.          * mblen() should return -1 for invalid (means the leading
  555.          * multibyte) character.  However there are some platform
  556.          * where mblen() returns 0 for invalid character.  Therefore,
  557.          * following condition includes 0.
  558.          */
  559.         buf[0] = i;
  560.         buf[1] = 0;
  561. #if 0
  562.         if (i >= 0x80)/* TESTING DBCS: 'encoding' != current locale */
  563. #else
  564.         if (mblen(buf, (size_t)1) <= 0)
  565. #endif
  566.             n = 2;
  567.         else
  568.             n = 1;
  569.         }
  570. # endif
  571. #endif
  572.     }
  573.  
  574.     mb_bytelen_tab[i] = n;
  575.     }
  576.  
  577.     /* The cell width depends on the type of multi-byte characters. */
  578.     (void)init_chartab();
  579.  
  580.     /* When enc_utf8 is set or reset, (de)allocate ScreenLinesUC[] */
  581.     screenalloc(FALSE);
  582.  
  583.     /* When using Unicode, set default for 'fileencodings'. */
  584.     if (enc_utf8 && !option_was_set((char_u *)"fencs"))
  585.     set_string_option_direct((char_u *)"fencs", -1,
  586.                  (char_u *)"ucs-bom,utf-8,latin1", OPT_FREE);
  587. #if defined(HAVE_BIND_TEXTDOMAIN_CODESET) && defined(FEAT_GETTEXT)
  588.     /* GNU gettext 0.10.37 supports this feature: set the codeset used for
  589.      * translated messages independently from the current locale. */
  590.     (void)bind_textdomain_codeset(VIMPACKAGE,
  591.                       enc_utf8 ? "utf-8" : (char *)p_enc);
  592. #endif
  593.  
  594. #ifdef FEAT_AUTOCMD
  595.     /* Fire an autocommand to let people do custom font setup. This must be
  596.      * after Vim has been setup for the new encoding. */
  597.     apply_autocmds(EVENT_ENCODINGCHANGED, NULL, (char_u *)"", FALSE, curbuf);
  598. #endif
  599.  
  600.     return NULL;
  601. }
  602.  
  603. /*
  604.  * Return the size of the BOM for the current buffer:
  605.  * 0 - no BOM
  606.  * 2 - UCS-2 or UTF-16 BOM
  607.  * 4 - UCS-4 BOM
  608.  * 3 - UTF-8 BOM
  609.  */
  610.     int
  611. bomb_size()
  612. {
  613.     int n = 0;
  614.  
  615.     if (curbuf->b_p_bomb && !curbuf->b_p_bin)
  616.     {
  617.     if (*curbuf->b_p_fenc == NUL)
  618.     {
  619.         if (enc_utf8)
  620.         {
  621.         if (enc_unicode != 0)
  622.             n = enc_unicode;
  623.         else
  624.             n = 3;
  625.         }
  626.     }
  627.     else if (STRCMP(curbuf->b_p_fenc, "utf-8") == 0)
  628.         n = 3;
  629.     else if (STRNCMP(curbuf->b_p_fenc, "ucs-2", 5) == 0
  630.         || STRNCMP(curbuf->b_p_fenc, "utf-16", 6) == 0)
  631.         n = 2;
  632.     else if (STRNCMP(curbuf->b_p_fenc, "ucs-4", 5) == 0)
  633.         n = 4;
  634.     }
  635.     return n;
  636. }
  637.  
  638. /*
  639.  * Get class of pointer:
  640.  * 0 for blank or NUL
  641.  * 1 for punctuation
  642.  * 2 for an (ASCII) word character
  643.  * >2 for other word characters
  644.  */
  645.     int
  646. mb_get_class(p)
  647.     char_u    *p;
  648. {
  649.     if (MB_BYTE2LEN(p[0]) == 1)
  650.     {
  651.     if (p[0] == NUL || vim_iswhite(p[0]))
  652.         return 0;
  653.     if (vim_iswordc(p[0]))
  654.         return 2;
  655.     return 1;
  656.     }
  657.     if (enc_dbcs != 0 && p[0] != NUL && p[1] != NUL)
  658.     return dbcs_class(p[0], p[1]);
  659.     if (enc_utf8)
  660.     return utf_class(utf_ptr2char(p));
  661.     return 0;
  662. }
  663.  
  664. /*
  665.  * Get class of a double-byte character.  This always returns 3 or bigger.
  666.  * TODO: Should return 1 for punctuation.
  667.  */
  668.     int
  669. dbcs_class(lead, trail)
  670.     unsigned    lead;
  671.     unsigned    trail;
  672. {
  673.     switch (enc_dbcs)
  674.     {
  675.     /* please add classfy routine for your language in here */
  676.  
  677.     case DBCS_JPNU:    /* ? */
  678.     case DBCS_JPN:
  679.         {
  680.         /* JIS code classification */
  681.         unsigned char lb = lead;
  682.         unsigned char tb = trail;
  683.  
  684.         /* convert process code to JIS */
  685. # if defined(WIN3264) || defined(WIN32UNIX) || defined(MACOS)
  686.         /* process code is SJIS */
  687.         if (lb <= 0x9f)
  688.             lb = (lb - 0x81) * 2 + 0x21;
  689.         else
  690.             lb = (lb - 0xc1) * 2 + 0x21;
  691.         if (tb <= 0x7e)
  692.             tb -= 0x1f;
  693.         else if (tb <= 0x9e)
  694.             tb -= 0x20;
  695.         else
  696.         {
  697.             tb -= 0x7e;
  698.             lb += 1;
  699.         }
  700. # else
  701.         /*
  702.          * XXX: Code page identification can not use with all
  703.          *        system! So, some other encoding information
  704.          *        will be needed.
  705.          *        In japanese: SJIS,EUC,UNICODE,(JIS)
  706.          *        Note that JIS-code system don't use as
  707.          *        process code in most system because it uses
  708.          *        escape sequences(JIS is context depend encoding).
  709.          */
  710.         /* assume process code is JAPANESE-EUC */
  711.         lb &= 0x7f;
  712.         tb &= 0x7f;
  713. # endif
  714.         /* exceptions */
  715.         switch (lb << 8 | tb)
  716.         {
  717.             case 0x2121: /* ZENKAKU space */
  718.             return 0;
  719.             case 0x2122: /* KU-TEN (Japanese comma) */
  720.             case 0x2123: /* TOU-TEN (Japanese period) */
  721.             case 0x2124: /* ZENKAKU comma */
  722.             case 0x2125: /* ZENKAKU period */
  723.             return 1;
  724.             case 0x213c: /* prolongedsound handled as KATAKANA */
  725.             return 13;
  726.         }
  727.         /* sieved by KU code */
  728.         switch (lb)
  729.         {
  730.             case 0x21:
  731.             case 0x22:
  732.             /* special symbols */
  733.             return 10;
  734.             case 0x23:
  735.             /* alpha-numeric */
  736.             return 11;
  737.             case 0x24:
  738.             /* hiragana */
  739.             return 12;
  740.             case 0x25:
  741.             /* katakana */
  742.             return 13;
  743.             case 0x26:
  744.             /* greek */
  745.             return 14;
  746.             case 0x27:
  747.             /* russian */
  748.             return 15;
  749.             case 0x28:
  750.             /* lines */
  751.             return 16;
  752.             default:
  753.             /* kanji */
  754.             return 17;
  755.         }
  756.         }
  757.  
  758.     case DBCS_KORU:    /* ? */
  759.     case DBCS_KOR:
  760.         {
  761.         /* KS code classification */
  762.         unsigned char c1 = lead;
  763.         unsigned char c2 = trail;
  764.  
  765.         /*
  766.          * 20 : Hangul
  767.          * 21 : Hanja
  768.          * 22 : Symbols
  769.          * 23 : Alpha-numeric/Roman Letter (Full width)
  770.          * 24 : Hangul Letter(Alphabet)
  771.          * 25 : Roman Numeral/Greek Letter
  772.          * 26 : Box Drawings
  773.          * 27 : Unit Symbols
  774.          * 28 : Circled/Parenthesized Letter
  775.          * 29 : Hirigana/Katakana
  776.          * 30 : Cyrillic Letter
  777.          */
  778.  
  779.         if (c1 >= 0xB0 && c1 <= 0xC8)
  780.             /* Hangul */
  781.             return 20;
  782. #if defined(WIN3264) || defined(WIN32UNIX)
  783.         else if (c1 <= 0xA0 || c2 <= 0xA0)
  784.             /* Extended Hangul Region : MS UHC(Unified Hangul Code) */
  785.             /* c1: 0x81-0xA0 with c2: 0x41-0x5A, 0x61-0x7A, 0x81-0xFE
  786.              * c1: 0xA1-0xC6 with c2: 0x41-0x5A, 0x61-0x7A, 0x81-0xA0
  787.              */
  788.             return 20;
  789. #endif
  790.  
  791.         else if (c1 >= 0xCA && c1 <= 0xFD)
  792.             /* Hanja */
  793.             return 21;
  794.         else switch (c1)
  795.         {
  796.             case 0xA1:
  797.             case 0xA2:
  798.             /* Symbols */
  799.             return 22;
  800.             case 0xA3:
  801.             /* Alpha-numeric */
  802.             return 23;
  803.             case 0xA4:
  804.             /* Hangul Letter(Alphabet) */
  805.             return 24;
  806.             case 0xA5:
  807.             /* Roman Numeral/Greek Letter */
  808.             return 25;
  809.             case 0xA6:
  810.             /* Box Drawings */
  811.             return 26;
  812.             case 0xA7:
  813.             /* Unit Symbols */
  814.             return 27;
  815.             case 0xA8:
  816.             case 0xA9:
  817.             if (c2 <= 0xAF)
  818.                 return 25;  /* Roman Letter */
  819.             else if (c2 >= 0xF6)
  820.                 return 22;  /* Symbols */
  821.             else
  822.                 /* Circled/Parenthesized Letter */
  823.                 return 28;
  824.             case 0xAA:
  825.             case 0xAB:
  826.             /* Hirigana/Katakana */
  827.             return 29;
  828.             case 0xAC:
  829.             /* Cyrillic Letter */
  830.             return 30;
  831.         }
  832.         }
  833.     default:
  834.         break;
  835.     }
  836.     return 3;
  837. }
  838.  
  839. /*
  840.  * mb_char2len() function pointer.
  841.  * Return length in bytes of character "c".
  842.  * Returns 1 for a single-byte character.
  843.  */
  844. /* ARGSUSED */
  845.     int
  846. latin_char2len(c)
  847.     int        c;
  848. {
  849.     return 1;
  850. }
  851.  
  852.     static int
  853. dbcs_char2len(c)
  854.     int        c;
  855. {
  856.     if (c >= 0x100)
  857.     return 2;
  858.     return 1;
  859. }
  860.  
  861. /*
  862.  * mb_char2bytes() function pointer.
  863.  * Convert a character to its bytes.
  864.  * Returns the length in bytes.
  865.  */
  866.     int
  867. latin_char2bytes(c, buf)
  868.     int        c;
  869.     char_u    *buf;
  870. {
  871.     buf[0] = c;
  872.     return 1;
  873. }
  874.  
  875.     static int
  876. dbcs_char2bytes(c, buf)
  877.     int        c;
  878.     char_u    *buf;
  879. {
  880.     if (c >= 0x100)
  881.     {
  882.     buf[0] = (unsigned)c >> 8;
  883.     buf[1] = c;
  884.     return 2;
  885.     }
  886.     buf[0] = c;
  887.     return 1;
  888. }
  889.  
  890. /*
  891.  * mb_ptr2len_check() function pointer.
  892.  * Get byte length of character at "*p" but stop at a NUL.
  893.  * For UTF-8 this includes following composing characters.
  894.  * Returns 0 when *p is NUL.
  895.  *
  896.  */
  897.     int
  898. latin_ptr2len_check(p)
  899.     char_u    *p;
  900. {
  901.     return MB_BYTE2LEN(*p);
  902. }
  903.  
  904.     static int
  905. dbcs_ptr2len_check(p)
  906.     char_u    *p;
  907. {
  908.     int        len;
  909.  
  910.     /* Check if second byte is not missing. */
  911.     len = MB_BYTE2LEN(*p);
  912.     if (len == 2 && p[1] == NUL)
  913.     len = 1;
  914.     return len;
  915. }
  916.  
  917. struct interval
  918. {
  919.     unsigned short first;
  920.     unsigned short last;
  921. };
  922. static int intable __ARGS((struct interval *table, size_t size, int c));
  923.  
  924. /*
  925.  * Return TRUE if "c" is in "table[size / sizeof(struct interval)]".
  926.  */
  927.     static int
  928. intable(table, size, c)
  929.     struct interval    *table;
  930.     size_t        size;
  931.     int            c;
  932. {
  933.     int mid, bot, top;
  934.  
  935.     /* first quick check for Latin1 etc. characters */
  936.     if (c < table[0].first)
  937.     return FALSE;
  938.  
  939.     /* binary search in table */
  940.     bot = 0;
  941.     top = size / sizeof(struct interval) - 1;
  942.     while (top >= bot)
  943.     {
  944.     mid = (bot + top) / 2;
  945.     if (table[mid].last < c)
  946.         bot = mid + 1;
  947.     else if (table[mid].first > c)
  948.         top = mid - 1;
  949.     else
  950.         return TRUE;
  951.     }
  952.     return FALSE;
  953. }
  954.  
  955. /*
  956.  * For UTF-8 character "c" return 2 for a double-width character, 1 for others.
  957.  * Returns 4 or 6 for an unprintable character.
  958.  * Is only correct for characters >= 0x80.
  959.  * When p_ambw is "double", return 2 for a character with East Asian Width
  960.  * class 'A'(mbiguous).
  961.  */
  962.     int
  963. utf_char2cells(c)
  964.     int        c;
  965. {
  966.     /* sorted list of non-overlapping intervals of East Asian Ambiguous
  967.      * characters, generated with:
  968.      * "uniset +WIDTH-A -cat=Me -cat=Mn -cat=Cf c" */
  969.     static struct interval ambiguous[] = {
  970.     {0x00A1, 0x00A1}, {0x00A4, 0x00A4}, {0x00A7, 0x00A8},
  971.     {0x00AA, 0x00AA}, {0x00AE, 0x00AE}, {0x00B0, 0x00B4},
  972.     {0x00B6, 0x00BA}, {0x00BC, 0x00BF}, {0x00C6, 0x00C6},
  973.     {0x00D0, 0x00D0}, {0x00D7, 0x00D8}, {0x00DE, 0x00E1},
  974.     {0x00E6, 0x00E6}, {0x00E8, 0x00EA}, {0x00EC, 0x00ED},
  975.     {0x00F0, 0x00F0}, {0x00F2, 0x00F3}, {0x00F7, 0x00FA},
  976.     {0x00FC, 0x00FC}, {0x00FE, 0x00FE}, {0x0101, 0x0101},
  977.     {0x0111, 0x0111}, {0x0113, 0x0113}, {0x011B, 0x011B},
  978.     {0x0126, 0x0127}, {0x012B, 0x012B}, {0x0131, 0x0133},
  979.     {0x0138, 0x0138}, {0x013F, 0x0142}, {0x0144, 0x0144},
  980.     {0x0148, 0x014B}, {0x014D, 0x014D}, {0x0152, 0x0153},
  981.     {0x0166, 0x0167}, {0x016B, 0x016B}, {0x01CE, 0x01CE},
  982.     {0x01D0, 0x01D0}, {0x01D2, 0x01D2}, {0x01D4, 0x01D4},
  983.     {0x01D6, 0x01D6}, {0x01D8, 0x01D8}, {0x01DA, 0x01DA},
  984.     {0x01DC, 0x01DC}, {0x0251, 0x0251}, {0x0261, 0x0261},
  985.     {0x02C4, 0x02C4}, {0x02C7, 0x02C7}, {0x02C9, 0x02CB},
  986.     {0x02CD, 0x02CD}, {0x02D0, 0x02D0}, {0x02D8, 0x02DB},
  987.     {0x02DD, 0x02DD}, {0x02DF, 0x02DF}, {0x0391, 0x03A1},
  988.     {0x03A3, 0x03A9}, {0x03B1, 0x03C1}, {0x03C3, 0x03C9},
  989.     {0x0401, 0x0401}, {0x0410, 0x044F}, {0x0451, 0x0451},
  990.     {0x2010, 0x2010}, {0x2013, 0x2016}, {0x2018, 0x2019},
  991.     {0x201C, 0x201D}, {0x2020, 0x2022}, {0x2024, 0x2027},
  992.     {0x2030, 0x2030}, {0x2032, 0x2033}, {0x2035, 0x2035},
  993.     {0x203B, 0x203B}, {0x203E, 0x203E}, {0x2074, 0x2074},
  994.     {0x207F, 0x207F}, {0x2081, 0x2084}, {0x20AC, 0x20AC},
  995.     {0x2103, 0x2103}, {0x2105, 0x2105}, {0x2109, 0x2109},
  996.     {0x2113, 0x2113}, {0x2116, 0x2116}, {0x2121, 0x2122},
  997.     {0x2126, 0x2126}, {0x212B, 0x212B}, {0x2153, 0x2154},
  998.     {0x215B, 0x215E}, {0x2160, 0x216B}, {0x2170, 0x2179},
  999.     {0x2190, 0x2199}, {0x21B8, 0x21B9}, {0x21D2, 0x21D2},
  1000.     {0x21D4, 0x21D4}, {0x21E7, 0x21E7}, {0x2200, 0x2200},
  1001.     {0x2202, 0x2203}, {0x2207, 0x2208}, {0x220B, 0x220B},
  1002.     {0x220F, 0x220F}, {0x2211, 0x2211}, {0x2215, 0x2215},
  1003.     {0x221A, 0x221A}, {0x221D, 0x2220}, {0x2223, 0x2223},
  1004.     {0x2225, 0x2225}, {0x2227, 0x222C}, {0x222E, 0x222E},
  1005.     {0x2234, 0x2237}, {0x223C, 0x223D}, {0x2248, 0x2248},
  1006.     {0x224C, 0x224C}, {0x2252, 0x2252}, {0x2260, 0x2261},
  1007.     {0x2264, 0x2267}, {0x226A, 0x226B}, {0x226E, 0x226F},
  1008.     {0x2282, 0x2283}, {0x2286, 0x2287}, {0x2295, 0x2295},
  1009.     {0x2299, 0x2299}, {0x22A5, 0x22A5}, {0x22BF, 0x22BF},
  1010.     {0x2312, 0x2312}, {0x2460, 0x24E9}, {0x24EB, 0x254B},
  1011.     {0x2550, 0x2573}, {0x2580, 0x258F}, {0x2592, 0x2595},
  1012.     {0x25A0, 0x25A1}, {0x25A3, 0x25A9}, {0x25B2, 0x25B3},
  1013.     {0x25B6, 0x25B7}, {0x25BC, 0x25BD}, {0x25C0, 0x25C1},
  1014.     {0x25C6, 0x25C8}, {0x25CB, 0x25CB}, {0x25CE, 0x25D1},
  1015.     {0x25E2, 0x25E5}, {0x25EF, 0x25EF}, {0x2605, 0x2606},
  1016.     {0x2609, 0x2609}, {0x260E, 0x260F}, {0x2614, 0x2615},
  1017.     {0x261C, 0x261C}, {0x261E, 0x261E}, {0x2640, 0x2640},
  1018.     {0x2642, 0x2642}, {0x2660, 0x2661}, {0x2663, 0x2665},
  1019.     {0x2667, 0x266A}, {0x266C, 0x266D}, {0x266F, 0x266F},
  1020.     {0x273D, 0x273D}, {0x2776, 0x277F}, {0xE000, 0xF8FF},
  1021.     {0xFFFD, 0xFFFD}
  1022.     };
  1023.  
  1024.     if (c >= 0x100)
  1025.     {
  1026.     if (!utf_printable(c))
  1027.         return 6;        /* unprintable, displays <xxxx> */
  1028.     if (c >= 0x1100
  1029.         && (c <= 0x115f            /* Hangul Jamo */
  1030.         || c == 0x2329
  1031.         || c == 0x232a
  1032.         || (c >= 0x2e80 && c <= 0xa4cf
  1033.             && c != 0x303f)        /* CJK ... Yi */
  1034.         || (c >= 0xac00 && c <= 0xd7a3)    /* Hangul Syllables */
  1035.         || (c >= 0xf900 && c <= 0xfaff)    /* CJK Compatibility
  1036.                            Ideographs */
  1037.         || (c >= 0xfe30 && c <= 0xfe6f)    /* CJK Compatibility Forms */
  1038.         || (c >= 0xff00 && c <= 0xff60)    /* Fullwidth Forms */
  1039.         || (c >= 0xffe0 && c <= 0xffe6)
  1040.         || (c >= 0x20000 && c <= 0x2ffff)))
  1041.         return 2;
  1042.     }
  1043.  
  1044.     /* Characters below 0x100 are influenced by 'isprint' option */
  1045.     else if (c >= 0x80 && !vim_isprintc(c))
  1046.     return 4;        /* unprintable, displays <xx> */
  1047.  
  1048.     if (c >= 0x80 && *p_ambw == 'd' && intable(ambiguous, sizeof(ambiguous), c))
  1049.     return 2;
  1050.  
  1051.     return 1;
  1052. }
  1053.  
  1054. /*
  1055.  * mb_ptr2cells() function pointer.
  1056.  * Return the number of display cells character at "*p" occupies.
  1057.  * This doesn't take care of unprintable characters, use ptr2cells() for that.
  1058.  */
  1059. /*ARGSUSED*/
  1060.     int
  1061. latin_ptr2cells(p)
  1062.     char_u    *p;
  1063. {
  1064.     return 1;
  1065. }
  1066.  
  1067.     int
  1068. utf_ptr2cells(p)
  1069.     char_u    *p;
  1070. {
  1071.     int        c;
  1072.  
  1073.     /* Need to convert to a wide character. */
  1074.     if (*p >= 0x80)
  1075.     {
  1076.     c = utf_ptr2char(p);
  1077.     /* An illegal byte is displayed as <xx>. */
  1078.     if (utf_ptr2len_check(p) == 1 || c == NUL)
  1079.         return 4;
  1080.     /* If the char is ASCII it must be an overlong sequence. */
  1081.     if (c < 0x80)
  1082.         return char2cells(c);
  1083.     return utf_char2cells(c);
  1084.     }
  1085.     return 1;
  1086. }
  1087.  
  1088.     int
  1089. dbcs_ptr2cells(p)
  1090.     char_u    *p;
  1091. {
  1092.     /* Number of cells is equal to number of bytes, except for euc-jp when
  1093.      * the first byte is 0x8e. */
  1094.     if (enc_dbcs == DBCS_JPNU && *p == 0x8e)
  1095.     return 1;
  1096.     return MB_BYTE2LEN(*p);
  1097. }
  1098.  
  1099. /*
  1100.  * mb_char2cells() function pointer.
  1101.  * Return the number of display cells character "c" occupies.
  1102.  * Only takes care of multi-byte chars, not "^C" and such.
  1103.  */
  1104. /*ARGSUSED*/
  1105.     int
  1106. latin_char2cells(c)
  1107.     int        c;
  1108. {
  1109.     return 1;
  1110. }
  1111.  
  1112.     static int
  1113. dbcs_char2cells(c)
  1114.     int        c;
  1115. {
  1116.     /* Number of cells is equal to number of bytes, except for euc-jp when
  1117.      * the first byte is 0x8e. */
  1118.     if (enc_dbcs == DBCS_JPNU && ((unsigned)c >> 8) == 0x8e)
  1119.     return 1;
  1120.     /* use the first byte */
  1121.     return MB_BYTE2LEN((unsigned)c >> 8);
  1122. }
  1123.  
  1124. /*
  1125.  * mb_off2cells() function pointer.
  1126.  * Return number of display cells for char at ScreenLines[off].
  1127.  * Caller must make sure "off" and "off + 1" are valid!
  1128.  */
  1129. /*ARGSUSED*/
  1130.     int
  1131. latin_off2cells(off)
  1132.     unsigned    off;
  1133. {
  1134.     return 1;
  1135. }
  1136.  
  1137.     int
  1138. dbcs_off2cells(off)
  1139.     unsigned    off;
  1140. {
  1141.     /* Number of cells is equal to number of bytes, except for euc-jp when
  1142.      * the first byte is 0x8e. */
  1143.     if (enc_dbcs == DBCS_JPNU && ScreenLines[off] == 0x8e)
  1144.     return 1;
  1145.     return MB_BYTE2LEN(ScreenLines[off]);
  1146. }
  1147.  
  1148.     int
  1149. utf_off2cells(off)
  1150.     unsigned    off;
  1151. {
  1152.     return ScreenLines[off + 1] == 0 ? 2 : 1;
  1153. }
  1154.  
  1155. /*
  1156.  * mb_ptr2char() function pointer.
  1157.  * Convert a byte sequence into a character.
  1158.  */
  1159.     int
  1160. latin_ptr2char(p)
  1161.     char_u    *p;
  1162. {
  1163.     return *p;
  1164. }
  1165.  
  1166.     static int
  1167. dbcs_ptr2char(p)
  1168.     char_u    *p;
  1169. {
  1170.     if (MB_BYTE2LEN(*p) > 1 && p[1] != NUL)
  1171.     return (p[0] << 8) + p[1];
  1172.     return *p;
  1173. }
  1174.  
  1175. /*
  1176.  * Convert a UTF-8 byte sequence to a wide character.
  1177.  * If the sequence is illegal or truncated by a NUL the first byte is
  1178.  * returned.
  1179.  * Does not include composing characters, of course.
  1180.  */
  1181.     int
  1182. utf_ptr2char(p)
  1183.     char_u    *p;
  1184. {
  1185.     int        len;
  1186.  
  1187.     if (p[0] < 0x80)    /* be quick for ASCII */
  1188.     return p[0];
  1189.  
  1190.     len = utf8len_tab[p[0]];
  1191.     if ((p[1] & 0xc0) == 0x80)
  1192.     {
  1193.     if (len == 2)
  1194.         return ((p[0] & 0x1f) << 6) + (p[1] & 0x3f);
  1195.     if ((p[2] & 0xc0) == 0x80)
  1196.     {
  1197.         if (len == 3)
  1198.         return ((p[0] & 0x0f) << 12) + ((p[1] & 0x3f) << 6)
  1199.             + (p[2] & 0x3f);
  1200.         if ((p[3] & 0xc0) == 0x80)
  1201.         {
  1202.         if (len == 4)
  1203.             return ((p[0] & 0x07) << 18) + ((p[1] & 0x3f) << 12)
  1204.             + ((p[2] & 0x3f) << 6) + (p[3] & 0x3f);
  1205.         if ((p[4] & 0xc0) == 0x80)
  1206.         {
  1207.             if (len == 5)
  1208.             return ((p[0] & 0x03) << 24) + ((p[1] & 0x3f) << 18)
  1209.                 + ((p[2] & 0x3f) << 12) + ((p[3] & 0x3f) << 6)
  1210.                 + (p[4] & 0x3f);
  1211.             if ((p[5] & 0xc0) == 0x80 && len == 6)
  1212.             return ((p[0] & 0x01) << 30) + ((p[1] & 0x3f) << 24)
  1213.                 + ((p[2] & 0x3f) << 18) + ((p[3] & 0x3f) << 12)
  1214.                 + ((p[4] & 0x3f) << 6) + (p[5] & 0x3f);
  1215.         }
  1216.         }
  1217.     }
  1218.     }
  1219.     /* Illegal value, just return the first byte */
  1220.     return p[0];
  1221. }
  1222.  
  1223. /*
  1224.  * Get character at **pp and advance *pp to the next character.
  1225.  * Note: composing characters are skipped!
  1226.  */
  1227.     int
  1228. mb_ptr2char_adv(pp)
  1229.     char_u    **pp;
  1230. {
  1231.     int        c;
  1232.  
  1233.     c = (*mb_ptr2char)(*pp);
  1234.     *pp += (*mb_ptr2len_check)(*pp);
  1235.     return c;
  1236. }
  1237.  
  1238. #if defined(FEAT_ARABIC) || defined(PROTO)
  1239. /*
  1240.  * Check whether we are dealing with Arabic combining characters.
  1241.  * Note: these are NOT really composing characters!
  1242.  */
  1243.     int
  1244. arabic_combine(one, two)
  1245.     int        one;        /* first character */
  1246.     int        two;        /* character just after "one" */
  1247. {
  1248.     if (one == a_LAM)
  1249.     return arabic_maycombine(two);
  1250.     return FALSE;
  1251. }
  1252.  
  1253. /*
  1254.  * Check whether we are dealing with a character that could be regarded as an
  1255.  * Arabic combining character, need to check the character before this.
  1256.  */
  1257.     int
  1258. arabic_maycombine(two)
  1259.     int        two;
  1260. {
  1261.     if (p_arshape && !p_tbidi)
  1262.     return (two == a_ALEF_MADDA
  1263.             || two == a_ALEF_HAMZA_ABOVE
  1264.             || two == a_ALEF_HAMZA_BELOW
  1265.             || two == a_ALEF);
  1266.     return FALSE;
  1267. }
  1268.  
  1269. /*
  1270.  * Check if the character pointed to by "p2" is a composing character when it
  1271.  * comes after "p1".  For Arabic sometimes "ab" is replaced with "c", which
  1272.  * behaves like a composing character.
  1273.  */
  1274.     int
  1275. utf_composinglike(p1, p2)
  1276.     char_u    *p1;
  1277.     char_u    *p2;
  1278. {
  1279.     int        c2;
  1280.  
  1281.     c2 = utf_ptr2char(p2);
  1282.     if (utf_iscomposing(c2))
  1283.     return TRUE;
  1284.     if (!arabic_maycombine(c2))
  1285.     return FALSE;
  1286.     return arabic_combine(utf_ptr2char(p1), c2);
  1287. }
  1288. #endif
  1289.  
  1290. /*
  1291.  * Convert a UTF-8 byte string to a wide chararacter.  Also get up to two
  1292.  * composing characters.
  1293.  */
  1294.     int
  1295. utfc_ptr2char(p, p1, p2)
  1296.     char_u    *p;
  1297.     int        *p1;    /* return: first composing char or 0 */
  1298.     int        *p2;    /* return: second composing char or 0 */
  1299. {
  1300.     int        len;
  1301.     int        c;
  1302.     int        cc;
  1303.  
  1304.     c = utf_ptr2char(p);
  1305.     len = utf_ptr2len_check(p);
  1306.     /* Only accept a composing char when the first char isn't illegal. */
  1307.     if ((len > 1 || *p < 0x80)
  1308.         && p[len] >= 0x80
  1309.         && UTF_COMPOSINGLIKE(p, p + len))
  1310.     {
  1311.     *p1 = utf_ptr2char(p + len);
  1312.     len += utf_ptr2len_check(p + len);
  1313.     if (p[len] >= 0x80 && utf_iscomposing(cc = utf_ptr2char(p + len)))
  1314.         *p2 = cc;
  1315.     else
  1316.         *p2 = 0;
  1317.     }
  1318.     else
  1319.     {
  1320.     *p1 = 0;
  1321.     *p2 = 0;
  1322.     }
  1323.     return c;
  1324. }
  1325.  
  1326. /*
  1327.  * Convert a UTF-8 byte string to a wide chararacter.  Also get up to two
  1328.  * composing characters.  Use no more than p[maxlen].
  1329.  */
  1330.     int
  1331. utfc_ptr2char_len(p, p1, p2, maxlen)
  1332.     char_u    *p;
  1333.     int        *p1;    /* return: first composing char or 0 */
  1334.     int        *p2;    /* return: second composing char or 0 */
  1335.     int        maxlen;
  1336. {
  1337.     int        len;
  1338.     int        c;
  1339.     int        cc;
  1340.  
  1341.     c = utf_ptr2char(p);
  1342.     len = utf_ptr2len_check_len(p, maxlen);
  1343.     /* Only accept a composing char when the first char isn't illegal. */
  1344.     if ((len > 1 || *p < 0x80)
  1345.         && len < maxlen
  1346.         && p[len] >= 0x80
  1347.         && UTF_COMPOSINGLIKE(p, p + len))
  1348.     {
  1349.     *p1 = utf_ptr2char(p + len);
  1350.     len += utf_ptr2len_check_len(p + len, maxlen - len);
  1351.     if (len < maxlen
  1352.         && p[len] >= 0x80
  1353.         && utf_iscomposing(cc = utf_ptr2char(p + len)))
  1354.         *p2 = cc;
  1355.     else
  1356.         *p2 = 0;
  1357.     }
  1358.     else
  1359.     {
  1360.     *p1 = 0;
  1361.     *p2 = 0;
  1362.     }
  1363.     return c;
  1364. }
  1365.  
  1366. /*
  1367.  * Convert the character at screen position "off" to a sequence of bytes.
  1368.  * Includes the composing characters.
  1369.  * "buf" must at least have the length MB_MAXBYTES.
  1370.  * Returns the produced number of bytes.
  1371.  */
  1372.     int
  1373. utfc_char2bytes(off, buf)
  1374.     int        off;
  1375.     char_u    *buf;
  1376. {
  1377.     int        len;
  1378.  
  1379.     len = utf_char2bytes(ScreenLinesUC[off], buf);
  1380.     if (ScreenLinesC1[off] != 0)
  1381.     {
  1382.     len += utf_char2bytes(ScreenLinesC1[off], buf + len);
  1383.     if (ScreenLinesC2[off] != 0)
  1384.         len += utf_char2bytes(ScreenLinesC2[off], buf + len);
  1385.     }
  1386.     return len;
  1387. }
  1388.  
  1389. /*
  1390.  * Get the length of a UTF-8 byte sequence, not including any following
  1391.  * composing characters.
  1392.  * Returns 0 for "".
  1393.  * Returns 1 for an illegal byte sequence.
  1394.  */
  1395.     int
  1396. utf_ptr2len_check(p)
  1397.     char_u    *p;
  1398. {
  1399.     int        len;
  1400.     int        i;
  1401.  
  1402.     if (*p == NUL)
  1403.     return 0;
  1404.     len = utf8len_tab[*p];
  1405.     for (i = 1; i < len; ++i)
  1406.     if ((p[i] & 0xc0) != 0x80)
  1407.         return 1;
  1408.     return len;
  1409. }
  1410.  
  1411. /*
  1412.  * Return length of UTF-8 character, obtained from the first byte.
  1413.  * "b" must be between 0 and 255!
  1414.  */
  1415.     int
  1416. utf_byte2len(b)
  1417.     int        b;
  1418. {
  1419.     return utf8len_tab[b];
  1420. }
  1421.  
  1422. /*
  1423.  * Get the length of UTF-8 byte sequence "p[size]".  Does not include any
  1424.  * following composing characters.
  1425.  * Returns 1 for "".
  1426.  * Returns 1 for an illegal byte sequence.
  1427.  * Returns number > "size" for an incomplete byte sequence.
  1428.  */
  1429.     int
  1430. utf_ptr2len_check_len(p, size)
  1431.     char_u    *p;
  1432.     int        size;
  1433. {
  1434.     int        len;
  1435.     int        i;
  1436.  
  1437.     if (*p == NUL)
  1438.     return 1;
  1439.     len = utf8len_tab[*p];
  1440.     for (i = 1; i < len && i < size; ++i)
  1441.     if ((p[i] & 0xc0) != 0x80)
  1442.         return 1;
  1443.     return len;
  1444. }
  1445.  
  1446. /*
  1447.  * Return the number of bytes the UTF-8 encoding of the character at "p" takes.
  1448.  * This includes following composing characters.
  1449.  */
  1450.     int
  1451. utfc_ptr2len_check(p)
  1452.     char_u    *p;
  1453. {
  1454.     int        len;
  1455. #ifdef FEAT_ARABIC
  1456.     int        prevlen;
  1457. #endif
  1458.  
  1459.     if (*p == NUL)
  1460.     return 0;
  1461.     if (p[0] < 0x80 && p[1] < 0x80)    /* be quick for ASCII */
  1462.     return 1;
  1463.  
  1464.     /* Skip over first UTF-8 char, stopping at a NUL byte. */
  1465.     len = utf_ptr2len_check(p);
  1466.  
  1467.     /* Check for illegal byte. */
  1468.     if (len == 1 && p[0] >= 0x80)
  1469.     return 1;
  1470.  
  1471.     /*
  1472.      * Check for composing characters.  We can handle only the first two, but
  1473.      * skip all of them (otherwise the cursor would get stuck).
  1474.      */
  1475. #ifdef FEAT_ARABIC
  1476.     prevlen = 0;
  1477. #endif
  1478.     for (;;)
  1479.     {
  1480.     if (p[len] < 0x80 || !UTF_COMPOSINGLIKE(p + prevlen, p + len))
  1481.         return len;
  1482.  
  1483.     /* Skip over composing char */
  1484. #ifdef FEAT_ARABIC
  1485.     prevlen = len;
  1486. #endif
  1487.     len += utf_ptr2len_check(p + len);
  1488.     }
  1489. }
  1490.  
  1491. /*
  1492.  * Return the number of bytes the UTF-8 encoding of the character at "p[size]"
  1493.  * takes.  This includes following composing characters.
  1494.  */
  1495.     int
  1496. utfc_ptr2len_check_len(p, size)
  1497.     char_u    *p;
  1498.     int        size;
  1499. {
  1500.     int        len;
  1501. #ifdef FEAT_ARABIC
  1502.     int        prevlen;
  1503. #endif
  1504.  
  1505.     if (*p == NUL)
  1506.     return 0;
  1507.     if (p[0] < 0x80 && (size == 1 || p[1] < 0x80)) /* be quick for ASCII */
  1508.     return 1;
  1509.  
  1510.     /* Skip over first UTF-8 char, stopping at a NUL byte. */
  1511.     len = utf_ptr2len_check_len(p, size);
  1512.  
  1513.     /* Check for illegal byte. */
  1514.     if (len == 1 && p[0] >= 0x80)
  1515.     return 1;
  1516.  
  1517.     /*
  1518.      * Check for composing characters.  We can handle only the first two, but
  1519.      * skip all of them (otherwise the cursor would get stuck).
  1520.      */
  1521. #ifdef FEAT_ARABIC
  1522.     prevlen = 0;
  1523. #endif
  1524.     while (len < size)
  1525.     {
  1526.     if (p[len] < 0x80 || !UTF_COMPOSINGLIKE(p + prevlen, p + len))
  1527.         break;
  1528.  
  1529.     /* Skip over composing char */
  1530. #ifdef FEAT_ARABIC
  1531.     prevlen = len;
  1532. #endif
  1533.     len += utf_ptr2len_check_len(p + len, size - len);
  1534.     }
  1535.     return len;
  1536. }
  1537.  
  1538. /*
  1539.  * Return the number of bytes the UTF-8 encoding of character "c" takes.
  1540.  * This does not include composing characters.
  1541.  */
  1542.     int
  1543. utf_char2len(c)
  1544.     int        c;
  1545. {
  1546.     if (c < 0x80)
  1547.     return 1;
  1548.     if (c < 0x800)
  1549.     return 2;
  1550.     if (c < 0x10000)
  1551.     return 3;
  1552.     if (c < 0x200000)
  1553.     return 4;
  1554.     if (c < 0x4000000)
  1555.     return 5;
  1556.     return 6;
  1557. }
  1558.  
  1559. /*
  1560.  * Convert Unicode character "c" to UTF-8 string in "buf[]".
  1561.  * Returns the number of bytes.
  1562.  * This does not include composing characters.
  1563.  */
  1564.     int
  1565. utf_char2bytes(c, buf)
  1566.     int        c;
  1567.     char_u    *buf;
  1568. {
  1569.     if (c < 0x80)        /* 7 bits */
  1570.     {
  1571.     buf[0] = c;
  1572.     return 1;
  1573.     }
  1574.     if (c < 0x800)        /* 11 bits */
  1575.     {
  1576.     buf[0] = 0xc0 + ((unsigned)c >> 6);
  1577.     buf[1] = 0x80 + (c & 0x3f);
  1578.     return 2;
  1579.     }
  1580.     if (c < 0x10000)        /* 16 bits */
  1581.     {
  1582.     buf[0] = 0xe0 + ((unsigned)c >> 12);
  1583.     buf[1] = 0x80 + (((unsigned)c >> 6) & 0x3f);
  1584.     buf[2] = 0x80 + (c & 0x3f);
  1585.     return 3;
  1586.     }
  1587.     if (c < 0x200000)        /* 21 bits */
  1588.     {
  1589.     buf[0] = 0xf0 + ((unsigned)c >> 18);
  1590.     buf[1] = 0x80 + (((unsigned)c >> 12) & 0x3f);
  1591.     buf[2] = 0x80 + (((unsigned)c >> 6) & 0x3f);
  1592.     buf[3] = 0x80 + (c & 0x3f);
  1593.     return 4;
  1594.     }
  1595.     if (c < 0x4000000)        /* 26 bits */
  1596.     {
  1597.     buf[0] = 0xf8 + ((unsigned)c >> 24);
  1598.     buf[1] = 0x80 + (((unsigned)c >> 18) & 0x3f);
  1599.     buf[2] = 0x80 + (((unsigned)c >> 12) & 0x3f);
  1600.     buf[3] = 0x80 + (((unsigned)c >> 6) & 0x3f);
  1601.     buf[4] = 0x80 + (c & 0x3f);
  1602.     return 5;
  1603.     }
  1604.                 /* 31 bits */
  1605.     buf[0] = 0xfc + ((unsigned)c >> 30);
  1606.     buf[1] = 0x80 + (((unsigned)c >> 24) & 0x3f);
  1607.     buf[2] = 0x80 + (((unsigned)c >> 18) & 0x3f);
  1608.     buf[3] = 0x80 + (((unsigned)c >> 12) & 0x3f);
  1609.     buf[4] = 0x80 + (((unsigned)c >> 6) & 0x3f);
  1610.     buf[5] = 0x80 + (c & 0x3f);
  1611.     return 6;
  1612. }
  1613.  
  1614. /*
  1615.  * Return TRUE if "c" is a composing UTF-8 character.  This means it will be
  1616.  * drawn on top of the preceding character.
  1617.  * Based on code from Markus Kuhn.
  1618.  */
  1619.     int
  1620. utf_iscomposing(c)
  1621.     int        c;
  1622. {
  1623.     /* sorted list of non-overlapping intervals */
  1624.     static struct interval combining[] =
  1625.     {
  1626.     {0x0300, 0x034f}, {0x0360, 0x036f}, {0x0483, 0x0486}, {0x0488, 0x0489},
  1627.     {0x0591, 0x05a1}, {0x05a3, 0x05b9}, {0x05bb, 0x05bd}, {0x05bf, 0x05bf},
  1628.     {0x05c1, 0x05c2}, {0x05c4, 0x05c4}, {0x0610, 0x0615}, {0x064b, 0x0658},
  1629.     {0x0670, 0x0670}, {0x06d6, 0x06dc}, {0x06de, 0x06e4}, {0x06e7, 0x06e8},
  1630.     {0x06ea, 0x06ed}, {0x0711, 0x0711}, {0x0730, 0x074a}, {0x07a6, 0x07b0},
  1631.     {0x0901, 0x0903}, {0x093c, 0x093c}, {0x093e, 0x094d}, {0x0951, 0x0954},
  1632.     {0x0962, 0x0963}, {0x0981, 0x0983}, {0x09bc, 0x09bc}, {0x09be, 0x09c4},
  1633.     {0x09c7, 0x09c8}, {0x09cb, 0x09cd}, {0x09d7, 0x09d7}, {0x09e2, 0x09e3},
  1634.     {0x0a01, 0x0a03}, {0x0a3c, 0x0a3c}, {0x0a3e, 0x0a42}, {0x0a47, 0x0a48},
  1635.     {0x0a4b, 0x0a4d}, {0x0a70, 0x0a71}, {0x0a81, 0x0a83}, {0x0abc, 0x0abc},
  1636.     {0x0abe, 0x0ac5}, {0x0ac7, 0x0ac9}, {0x0acb, 0x0acd}, {0x0ae2, 0x0ae3},
  1637.     {0x0b01, 0x0b03}, {0x0b3c, 0x0b3c}, {0x0b3e, 0x0b43}, {0x0b47, 0x0b48},
  1638.     {0x0b4b, 0x0b4d}, {0x0b56, 0x0b57}, {0x0b82, 0x0b82}, {0x0bbe, 0x0bc2},
  1639.     {0x0bc6, 0x0bc8}, {0x0bca, 0x0bcd}, {0x0bd7, 0x0bd7}, {0x0c01, 0x0c03},
  1640.     {0x0c3e, 0x0c44}, {0x0c46, 0x0c48}, {0x0c4a, 0x0c4d}, {0x0c55, 0x0c56},
  1641.     {0x0c82, 0x0c83}, {0x0cbc, 0x0cbc}, {0x0cbe, 0x0cc4}, {0x0cc6, 0x0cc8},
  1642.     {0x0cca, 0x0ccd}, {0x0cd5, 0x0cd6}, {0x0d02, 0x0d03}, {0x0d3e, 0x0d43},
  1643.     {0x0d46, 0x0d48}, {0x0d4a, 0x0d4d}, {0x0d57, 0x0d57}, {0x0d82, 0x0d83},
  1644.     {0x0dca, 0x0dca}, {0x0dcf, 0x0dd4}, {0x0dd6, 0x0dd6}, {0x0dd8, 0x0ddf},
  1645.     {0x0df2, 0x0df3}, {0x0e31, 0x0e31}, {0x0e34, 0x0e3a}, {0x0e47, 0x0e4e},
  1646.     {0x0eb1, 0x0eb1}, {0x0eb4, 0x0eb9}, {0x0ebb, 0x0ebc}, {0x0ec8, 0x0ecd},
  1647.     {0x0f18, 0x0f19}, {0x0f35, 0x0f35}, {0x0f37, 0x0f37}, {0x0f39, 0x0f39},
  1648.     {0x0f3e, 0x0f3f}, {0x0f71, 0x0f84}, {0x0f86, 0x0f87}, {0x0f90, 0x0f97},
  1649.     {0x0f99, 0x0fbc}, {0x0fc6, 0x0fc6}, {0x102c, 0x1032}, {0x1036, 0x1039},
  1650.     {0x1056, 0x1059}, {0x1712, 0x1714}, {0x1732, 0x1734}, {0x1752, 0x1753},
  1651.     {0x1772, 0x1773}, {0x17b6, 0x17d3}, {0x17dd, 0x17dd}, {0x180b, 0x180d},
  1652.     {0x18a9, 0x18a9}, {0x1920, 0x192b}, {0x1930, 0x193b}, {0x20d0, 0x20ea},
  1653.     {0x302a, 0x302f}, {0x3099, 0x309a}, {0xfb1e, 0xfb1e}, {0xfe00, 0xfe0f},
  1654.     {0xfe20, 0xfe23},
  1655.     };
  1656.  
  1657.     return intable(combining, sizeof(combining), c);
  1658. }
  1659.  
  1660. /*
  1661.  * Return TRUE for characters that can be displayed in a normal way.
  1662.  * Only for characters of 0x100 and above!
  1663.  */
  1664.     int
  1665. utf_printable(c)
  1666.     int        c;
  1667. {
  1668.     /* Sorted list of non-overlapping intervals.
  1669.      * 0xd800-0xdfff is reserved for UTF-16, actually illegal. */
  1670.     static struct interval nonprint[] =
  1671.     {
  1672.     {0x070f, 0x070f}, {0x180b, 0x180e}, {0x200b, 0x200f}, {0x202a, 0x202e},
  1673.     {0x206a, 0x206f}, {0xd800, 0xdfff}, {0xfeff, 0xfeff}, {0xfff9, 0xfffb},
  1674.     {0xfffe, 0xffff}
  1675.     };
  1676.  
  1677.     return !intable(nonprint, sizeof(nonprint), c);
  1678. }
  1679.  
  1680. /*
  1681.  * Get class of a Unicode character.
  1682.  * 0: white space
  1683.  * 1: punctuation
  1684.  * 2 or bigger: some class of word character.
  1685.  */
  1686.     int
  1687. utf_class(c)
  1688.     int        c;
  1689. {
  1690.     /* sorted list of non-overlapping intervals */
  1691.     static struct interval
  1692.     {
  1693.     unsigned short first;
  1694.     unsigned short last;
  1695.     unsigned short class;
  1696.     } classes[] =
  1697.     {
  1698.     {0x037e, 0x037e, 1},        /* Greek question mark */
  1699.     {0x0387, 0x0387, 1},        /* Greek ano teleia */
  1700.     {0x055a, 0x055f, 1},        /* Armenian punctuation */
  1701.     {0x0589, 0x0589, 1},        /* Armenian full stop */
  1702.     {0x05be, 0x05be, 1},
  1703.     {0x05c0, 0x05c0, 1},
  1704.     {0x05c3, 0x05c3, 1},
  1705.     {0x05f3, 0x05f4, 1},
  1706.     {0x060c, 0x060c, 1},
  1707.     {0x061b, 0x061b, 1},
  1708.     {0x061f, 0x061f, 1},
  1709.     {0x066a, 0x066d, 1},
  1710.     {0x06d4, 0x06d4, 1},
  1711.     {0x0700, 0x070d, 1},        /* Syriac punctuation */
  1712.     {0x0964, 0x0965, 1},
  1713.     {0x0970, 0x0970, 1},
  1714.     {0x0df4, 0x0df4, 1},
  1715.     {0x0e4f, 0x0e4f, 1},
  1716.     {0x0e5a, 0x0e5b, 1},
  1717.     {0x0f04, 0x0f12, 1},
  1718.     {0x0f3a, 0x0f3d, 1},
  1719.     {0x0f85, 0x0f85, 1},
  1720.     {0x104a, 0x104f, 1},        /* Myanmar punctuation */
  1721.     {0x10fb, 0x10fb, 1},        /* Georgian punctuation */
  1722.     {0x1361, 0x1368, 1},        /* Ethiopic punctuation */
  1723.     {0x166d, 0x166e, 1},        /* Canadian Syl. punctuation */
  1724.     {0x1680, 0x1680, 0},
  1725.     {0x169b, 0x169c, 1},
  1726.     {0x16eb, 0x16ed, 1},
  1727.     {0x1735, 0x1736, 1},
  1728.     {0x17d4, 0x17dc, 1},        /* Khmer punctuation */
  1729.     {0x1800, 0x180a, 1},        /* Mongolian punctuation */
  1730.     {0x2000, 0x200b, 0},        /* spaces */
  1731.     {0x200c, 0x2027, 1},        /* punctuation and symbols */
  1732.     {0x2028, 0x2029, 0},
  1733.     {0x202a, 0x202e, 1},        /* punctuation and symbols */
  1734.     {0x202f, 0x202f, 0},
  1735.     {0x2030, 0x205e, 1},        /* punctuation and symbols */
  1736.     {0x205f, 0x205f, 0},
  1737.     {0x2060, 0x27ff, 1},        /* punctuation and symbols */
  1738.     {0x2070, 0x207f, 0x2070},    /* superscript */
  1739.     {0x2080, 0x208f, 0x2080},    /* subscript */
  1740.     {0x2983, 0x2998, 1},
  1741.     {0x29d8, 0x29db, 1},
  1742.     {0x29fc, 0x29fd, 1},
  1743.     {0x3000, 0x3000, 0},        /* ideographic space */
  1744.     {0x3001, 0x3020, 1},        /* ideographic punctuation */
  1745.     {0x3030, 0x3030, 1},
  1746.     {0x303d, 0x303d, 1},
  1747.     {0x3040, 0x309f, 0x3040},    /* Hiragana */
  1748.     {0x30a0, 0x30ff, 0x30a0},    /* Katakana */
  1749.     {0x3300, 0x9fff, 0x4e00},    /* CJK Ideographs */
  1750.     {0xac00, 0xd7a3, 0xac00},    /* Hangul Syllables */
  1751.     {0xf900, 0xfaff, 0x4e00},    /* CJK Ideographs */
  1752.     {0xfd3e, 0xfd3f, 1},
  1753.     {0xfe30, 0xfe6b, 1},        /* punctuation forms */
  1754.     {0xff00, 0xff0f, 1},        /* half/fullwidth ASCII */
  1755.     {0xff1a, 0xff20, 1},        /* half/fullwidth ASCII */
  1756.     {0xff3b, 0xff40, 1},        /* half/fullwidth ASCII */
  1757.     {0xff5b, 0xff65, 1},        /* half/fullwidth ASCII */
  1758.     };
  1759.     int bot = 0;
  1760.     int top = sizeof(classes) / sizeof(struct interval) - 1;
  1761.     int mid;
  1762.  
  1763.     /* First quick check for Latin1 characters, use 'iskeyword'. */
  1764.     if (c < 0x100)
  1765.     {
  1766.     if (c == ' ' || c == '\t' || c == NUL)
  1767.         return 0;        /* blank */
  1768.     if (vim_iswordc(c))
  1769.         return 2;        /* word character */
  1770.     return 1;        /* punctuation */
  1771.     }
  1772.  
  1773.     /* binary search in table */
  1774.     while (top >= bot)
  1775.     {
  1776.     mid = (bot + top) / 2;
  1777.     if (classes[mid].last < c)
  1778.         bot = mid + 1;
  1779.     else if (classes[mid].first > c)
  1780.         top = mid - 1;
  1781.     else
  1782.         return (int)classes[mid].class;
  1783.     }
  1784.  
  1785.     /* most other characters are "word" characters */
  1786.     return 2;
  1787. }
  1788.  
  1789. /*
  1790.  * Code for Unicode case-dependent operations.  Based on notes in
  1791.  * http://www.unicode.org/Public/UNIDATA/CaseFolding.txt
  1792.  * This code uses simple case folding, not full case folding.
  1793.  */
  1794.  
  1795. /*
  1796.  * The following table is built by foldExtract.pl < CaseFolding.txt .
  1797.  * It must be in numeric order, because we use binary search on it.
  1798.  * An entry such as {0x41,0x5a,1,32} means that UCS-4 characters in the range
  1799.  * from 0x41 to 0x5a inclusive, stepping by 1, are folded by adding 32.
  1800.  */
  1801.  
  1802. typedef struct
  1803. {
  1804.     int rangeStart;
  1805.     int rangeEnd;
  1806.     int step;
  1807.     int offset;
  1808. } convertStruct;
  1809.  
  1810. convertStruct foldCase[] =
  1811. {
  1812.     {0x41,0x5a,1,32}, {0xc0,0xd6,1,32}, {0xd8,0xde,1,32},
  1813.     {0x100,0x12e,2,1}, {0x130,0x130,-1,-199}, {0x132,0x136,2,1},
  1814.     {0x139,0x147,2,1}, {0x14a,0x176,2,1}, {0x178,0x178,-1,-121},
  1815.     {0x179,0x17d,2,1}, {0x181,0x181,-1,210}, {0x182,0x184,2,1},
  1816.     {0x186,0x186,-1,206}, {0x187,0x187,-1,1}, {0x189,0x18a,1,205},
  1817.     {0x18b,0x18b,-1,1}, {0x18e,0x18e,-1,79}, {0x18f,0x18f,-1,202},
  1818.     {0x190,0x190,-1,203}, {0x191,0x191,-1,1}, {0x193,0x193,-1,205},
  1819.     {0x194,0x194,-1,207}, {0x196,0x196,-1,211}, {0x197,0x197,-1,209},
  1820.     {0x198,0x198,-1,1}, {0x19c,0x19c,-1,211}, {0x19d,0x19d,-1,213},
  1821.     {0x19f,0x19f,-1,214}, {0x1a0,0x1a4,2,1}, {0x1a6,0x1a6,-1,218},
  1822.     {0x1a7,0x1a7,-1,1}, {0x1a9,0x1a9,-1,218}, {0x1ac,0x1ac,-1,1},
  1823.     {0x1ae,0x1ae,-1,218}, {0x1af,0x1af,-1,1}, {0x1b1,0x1b2,1,217},
  1824.     {0x1b3,0x1b5,2,1}, {0x1b7,0x1b7,-1,219}, {0x1b8,0x1bc,4,1},
  1825.     {0x1c4,0x1c4,-1,2}, {0x1c5,0x1c5,-1,1}, {0x1c7,0x1c7,-1,2},
  1826.     {0x1c8,0x1c8,-1,1}, {0x1ca,0x1ca,-1,2}, {0x1cb,0x1db,2,1},
  1827.     {0x1de,0x1ee,2,1}, {0x1f1,0x1f1,-1,2}, {0x1f2,0x1f4,2,1},
  1828.     {0x1f6,0x1f6,-1,-97}, {0x1f7,0x1f7,-1,-56}, {0x1f8,0x21e,2,1},
  1829.     {0x220,0x220,-1,-130}, {0x222,0x232,2,1}, {0x386,0x386,-1,38},
  1830.     {0x388,0x38a,1,37}, {0x38c,0x38c,-1,64}, {0x38e,0x38f,1,63},
  1831.     {0x391,0x3a1,1,32}, {0x3a3,0x3ab,1,32}, {0x3d8,0x3ee,2,1},
  1832.     {0x3f4,0x3f4,-1,-60}, {0x3f7,0x3f7,-1,1}, {0x3f9,0x3f9,-1,-7},
  1833.     {0x3fa,0x3fa,-1,1}, {0x400,0x40f,1,80}, {0x410,0x42f,1,32},
  1834.     {0x460,0x480,2,1}, {0x48a,0x4be,2,1}, {0x4c1,0x4cd,2,1},
  1835.     {0x4d0,0x4f4,2,1}, {0x4f8,0x500,8,1}, {0x502,0x50e,2,1},
  1836.     {0x531,0x556,1,48}, {0x1e00,0x1e94,2,1}, {0x1ea0,0x1ef8,2,1},
  1837.     {0x1f08,0x1f0f,1,-8}, {0x1f18,0x1f1d,1,-8}, {0x1f28,0x1f2f,1,-8},
  1838.     {0x1f38,0x1f3f,1,-8}, {0x1f48,0x1f4d,1,-8}, {0x1f59,0x1f5f,2,-8},
  1839.     {0x1f68,0x1f6f,1,-8}, {0x1f88,0x1f8f,1,-8}, {0x1f98,0x1f9f,1,-8},
  1840.     {0x1fa8,0x1faf,1,-8}, {0x1fb8,0x1fb9,1,-8}, {0x1fba,0x1fbb,1,-74},
  1841.     {0x1fbc,0x1fbc,-1,-9}, {0x1fc8,0x1fcb,1,-86}, {0x1fcc,0x1fcc,-1,-9},
  1842.     {0x1fd8,0x1fd9,1,-8}, {0x1fda,0x1fdb,1,-100}, {0x1fe8,0x1fe9,1,-8},
  1843.     {0x1fea,0x1feb,1,-112}, {0x1fec,0x1fec,-1,-7}, {0x1ff8,0x1ff9,1,-128},
  1844.     {0x1ffa,0x1ffb,1,-126}, {0x1ffc,0x1ffc,-1,-9}, {0x2126,0x2126,-1,-7517},
  1845.     {0x212a,0x212a,-1,-8383}, {0x212b,0x212b,-1,-8262},
  1846.     {0x2160,0x216f,1,16}, {0x24b6,0x24cf,1,26}, {0xff21,0xff3a,1,32},
  1847.     {0x10400,0x10427,1,40}
  1848. };
  1849.  
  1850. static int utf_convert(int a, convertStruct table[], int tableSize);
  1851.  
  1852. /*
  1853.  * Generic conversion function for case operations.
  1854.  * Return the converted equivalent of "a", which is a UCS-4 character.  Use
  1855.  * the given conversion "table".  Uses binary search on "table".
  1856.  */
  1857.     static int
  1858. utf_convert(a, table, tableSize)
  1859.     int            a;
  1860.     convertStruct    table[];
  1861.     int            tableSize;
  1862. {
  1863.     int start, mid, end; /* indices into table */
  1864.  
  1865.     start = 0;
  1866.     end = tableSize / sizeof(convertStruct);
  1867.     while (start < end)
  1868.     {
  1869.     /* need to search further */
  1870.     mid = (end + start) /2;
  1871.     if (table[mid].rangeEnd < a)
  1872.         start = mid + 1;
  1873.     else
  1874.         end = mid;
  1875.     }
  1876.     if (table[start].rangeStart <= a && a <= table[start].rangeEnd
  1877.         && (a - table[start].rangeStart) % table[start].step == 0)
  1878.     return (a + table[start].offset);
  1879.     else
  1880.     return a;
  1881. }
  1882.  
  1883. /*
  1884.  * Return the folded-case equivalent of "a", which is a UCS-4 character.  Uses
  1885.  * simple case folding.
  1886.  */
  1887.     int
  1888. utf_fold(a)
  1889.     int        a;
  1890. {
  1891.     return utf_convert(a, foldCase, sizeof(foldCase));
  1892. }
  1893.  
  1894. /*
  1895.  * The following tables are built by upperLowerExtract.pl < UnicodeData.txt .
  1896.  * They must be in numeric order, because we use binary search on them.
  1897.  * An entry such as {0x41,0x5a,1,32} means that UCS-4 characters in the range
  1898.  * from 0x41 to 0x5a inclusive, stepping by 1, are switched to lower (for
  1899.  * example) by adding 32.
  1900.  */
  1901. convertStruct toLower[] =
  1902. {
  1903.     {0x41,0x5a,1,32}, {0xc0,0xd6,1,32}, {0xd8,0xde,1,32},
  1904.     {0x100,0x12e,2,1}, {0x130,0x130,-1,-199}, {0x132,0x136,2,1},
  1905.     {0x139,0x147,2,1}, {0x14a,0x176,2,1}, {0x178,0x178,-1,-121},
  1906.     {0x179,0x17d,2,1}, {0x181,0x181,-1,210}, {0x182,0x184,2,1},
  1907.     {0x186,0x186,-1,206}, {0x187,0x187,-1,1}, {0x189,0x18a,1,205},
  1908.     {0x18b,0x18b,-1,1}, {0x18e,0x18e,-1,79}, {0x18f,0x18f,-1,202},
  1909.     {0x190,0x190,-1,203}, {0x191,0x191,-1,1}, {0x193,0x193,-1,205},
  1910.     {0x194,0x194,-1,207}, {0x196,0x196,-1,211}, {0x197,0x197,-1,209},
  1911.     {0x198,0x198,-1,1}, {0x19c,0x19c,-1,211}, {0x19d,0x19d,-1,213},
  1912.     {0x19f,0x19f,-1,214}, {0x1a0,0x1a4,2,1}, {0x1a6,0x1a6,-1,218},
  1913.     {0x1a7,0x1a7,-1,1}, {0x1a9,0x1a9,-1,218}, {0x1ac,0x1ac,-1,1},
  1914.     {0x1ae,0x1ae,-1,218}, {0x1af,0x1af,-1,1}, {0x1b1,0x1b2,1,217},
  1915.     {0x1b3,0x1b5,2,1}, {0x1b7,0x1b7,-1,219}, {0x1b8,0x1bc,4,1},
  1916.     {0x1c4,0x1ca,3,2}, {0x1cd,0x1db,2,1}, {0x1de,0x1ee,2,1},
  1917.     {0x1f1,0x1f1,-1,2}, {0x1f4,0x1f4,-1,1}, {0x1f6,0x1f6,-1,-97},
  1918.     {0x1f7,0x1f7,-1,-56}, {0x1f8,0x21e,2,1}, {0x220,0x220,-1,-130},
  1919.     {0x222,0x232,2,1}, {0x386,0x386,-1,38}, {0x388,0x38a,1,37},
  1920.     {0x38c,0x38c,-1,64}, {0x38e,0x38f,1,63}, {0x391,0x3a1,1,32},
  1921.     {0x3a3,0x3ab,1,32}, {0x3d8,0x3ee,2,1}, {0x3f4,0x3f4,-1,-60},
  1922.     {0x3f7,0x3f7,-1,1}, {0x3f9,0x3f9,-1,-7}, {0x3fa,0x3fa,-1,1},
  1923.     {0x400,0x40f,1,80}, {0x410,0x42f,1,32}, {0x460,0x480,2,1},
  1924.     {0x48a,0x4be,2,1}, {0x4c1,0x4cd,2,1}, {0x4d0,0x4f4,2,1},
  1925.     {0x4f8,0x500,8,1}, {0x502,0x50e,2,1}, {0x531,0x556,1,48},
  1926.     {0x1e00,0x1e94,2,1}, {0x1ea0,0x1ef8,2,1}, {0x1f08,0x1f0f,1,-8},
  1927.     {0x1f18,0x1f1d,1,-8}, {0x1f28,0x1f2f,1,-8}, {0x1f38,0x1f3f,1,-8},
  1928.     {0x1f48,0x1f4d,1,-8}, {0x1f59,0x1f5f,2,-8}, {0x1f68,0x1f6f,1,-8},
  1929.     {0x1fb8,0x1fb9,1,-8}, {0x1fba,0x1fbb,1,-74}, {0x1fc8,0x1fcb,1,-86},
  1930.     {0x1fd8,0x1fd9,1,-8}, {0x1fda,0x1fdb,1,-100}, {0x1fe8,0x1fe9,1,-8},
  1931.     {0x1fea,0x1feb,1,-112}, {0x1fec,0x1fec,-1,-7}, {0x1ff8,0x1ff9,1,-128},
  1932.     {0x1ffa,0x1ffb,1,-126}, {0x2126,0x2126,-1,-7517}, {0x212a,0x212a,-1,-8383},
  1933.     {0x212b,0x212b,-1,-8262}, {0xff21,0xff3a,1,32}, {0x10400,0x10427,1,40}
  1934. };
  1935.  
  1936. convertStruct toUpper[] =
  1937. {
  1938.     {0x61,0x7a,1,-32}, {0xb5,0xb5,-1,743}, {0xe0,0xf6,1,-32},
  1939.     {0xf8,0xfe,1,-32}, {0xff,0xff,-1,121}, {0x101,0x12f,2,-1},
  1940.     {0x131,0x131,-1,-232}, {0x133,0x137,2,-1}, {0x13a,0x148,2,-1},
  1941.     {0x14b,0x177,2,-1}, {0x17a,0x17e,2,-1}, {0x17f,0x17f,-1,-300},
  1942.     {0x183,0x185,2,-1}, {0x188,0x18c,4,-1}, {0x192,0x192,-1,-1},
  1943.     {0x195,0x195,-1,97}, {0x199,0x199,-1,-1}, {0x19e,0x19e,-1,130},
  1944.     {0x1a1,0x1a5,2,-1}, {0x1a8,0x1ad,5,-1}, {0x1b0,0x1b4,4,-1},
  1945.     {0x1b6,0x1b9,3,-1}, {0x1bd,0x1bd,-1,-1}, {0x1bf,0x1bf,-1,56},
  1946.     {0x1c5,0x1c6,1,-1}, {0x1c8,0x1c9,1,-1}, {0x1cb,0x1cc,1,-1},
  1947.     {0x1ce,0x1dc,2,-1}, {0x1dd,0x1dd,-1,-79}, {0x1df,0x1ef,2,-1},
  1948.     {0x1f2,0x1f3,1,-1}, {0x1f5,0x1f9,4,-1}, {0x1fb,0x21f,2,-1},
  1949.     {0x223,0x233,2,-1}, {0x253,0x253,-1,-210}, {0x254,0x254,-1,-206},
  1950.     {0x256,0x257,1,-205}, {0x259,0x259,-1,-202}, {0x25b,0x25b,-1,-203},
  1951.     {0x260,0x260,-1,-205}, {0x263,0x263,-1,-207}, {0x268,0x268,-1,-209},
  1952.     {0x269,0x26f,6,-211}, {0x272,0x272,-1,-213}, {0x275,0x275,-1,-214},
  1953.     {0x280,0x283,3,-218}, {0x288,0x288,-1,-218}, {0x28a,0x28b,1,-217},
  1954.     {0x292,0x292,-1,-219}, {0x3ac,0x3ac,-1,-38}, {0x3ad,0x3af,1,-37},
  1955.     {0x3b1,0x3c1,1,-32}, {0x3c2,0x3c2,-1,-31}, {0x3c3,0x3cb,1,-32},
  1956.     {0x3cc,0x3cc,-1,-64}, {0x3cd,0x3ce,1,-63}, {0x3d0,0x3d0,-1,-62},
  1957.     {0x3d1,0x3d1,-1,-57}, {0x3d5,0x3d5,-1,-47}, {0x3d6,0x3d6,-1,-54},
  1958.     {0x3d9,0x3ef,2,-1}, {0x3f0,0x3f0,-1,-86}, {0x3f1,0x3f1,-1,-80},
  1959.     {0x3f2,0x3f2,-1,7}, {0x3f5,0x3f5,-1,-96}, {0x3f8,0x3fb,3,-1},
  1960.     {0x430,0x44f,1,-32}, {0x450,0x45f,1,-80}, {0x461,0x481,2,-1},
  1961.     {0x48b,0x4bf,2,-1}, {0x4c2,0x4ce,2,-1}, {0x4d1,0x4f5,2,-1},
  1962.     {0x4f9,0x501,8,-1}, {0x503,0x50f,2,-1}, {0x561,0x586,1,-48},
  1963.     {0x1e01,0x1e95,2,-1}, {0x1e9b,0x1e9b,-1,-59}, {0x1ea1,0x1ef9,2,-1},
  1964.     {0x1f00,0x1f07,1,8}, {0x1f10,0x1f15,1,8}, {0x1f20,0x1f27,1,8},
  1965.     {0x1f30,0x1f37,1,8}, {0x1f40,0x1f45,1,8}, {0x1f51,0x1f57,2,8},
  1966.     {0x1f60,0x1f67,1,8}, {0x1f70,0x1f71,1,74}, {0x1f72,0x1f75,1,86},
  1967.     {0x1f76,0x1f77,1,100}, {0x1f78,0x1f79,1,128}, {0x1f7a,0x1f7b,1,112},
  1968.     {0x1f7c,0x1f7d,1,126}, {0x1f80,0x1f87,1,8}, {0x1f90,0x1f97,1,8},
  1969.     {0x1fa0,0x1fa7,1,8}, {0x1fb0,0x1fb1,1,8}, {0x1fb3,0x1fb3,-1,9},
  1970.     {0x1fbe,0x1fbe,-1,-7205}, {0x1fc3,0x1fc3,-1,9}, {0x1fd0,0x1fd1,1,8},
  1971.     {0x1fe0,0x1fe1,1,8}, {0x1fe5,0x1fe5,-1,7}, {0x1ff3,0x1ff3,-1,9},
  1972.     {0xff41,0xff5a,1,-32}, {0x10428,0x1044f,1,-40}
  1973. };
  1974.  
  1975. /*
  1976.  * Return the upper-case equivalent of "a", which is a UCS-4 character.  Use
  1977.  * simple case folding.
  1978.  */
  1979.     int
  1980. utf_toupper(a)
  1981.     int        a;
  1982. {
  1983.     /* If 'casemap' contains "keepascii" use ASCII style toupper(). */
  1984.     if (a < 128 && (cmp_flags & CMP_KEEPASCII))
  1985.     return TOUPPER_ASC(a);
  1986.  
  1987. #if defined(HAVE_TOWUPPER) && defined(__STDC__ISO_10646__)
  1988.     /* If towupper() is availble and handles Unicode, use it. */
  1989.     if (!(cmp_flags & CMP_INTERNAL))
  1990.     return towupper(a);
  1991. #endif
  1992.  
  1993.     /* For characters below 128 use locale sensitive toupper(). */
  1994.     if (a < 128)
  1995.     return TOUPPER_LOC(a);
  1996.  
  1997.     /* For any other characters use the above mapping table. */
  1998.     return utf_convert(a, toUpper, sizeof(toUpper));
  1999. }
  2000.  
  2001.     int
  2002. utf_islower(a)
  2003.     int        a;
  2004. {
  2005.     return (utf_toupper(a) != a);
  2006. }
  2007.  
  2008. /*
  2009.  * Return the lower-case equivalent of "a", which is a UCS-4 character.  Use
  2010.  * simple case folding.
  2011.  */
  2012.     int
  2013. utf_tolower(a)
  2014.     int        a;
  2015. {
  2016.     /* If 'casemap' contains "keepascii" use ASCII style tolower(). */
  2017.     if (a < 128 && (cmp_flags & CMP_KEEPASCII))
  2018.     return TOLOWER_ASC(a);
  2019.  
  2020. #if defined(HAVE_TOWLOWER) && defined(__STDC__ISO_10646__)
  2021.     /* If towlower() is availble and handles Unicode, use it. */
  2022.     if (!(cmp_flags & CMP_INTERNAL))
  2023.     return towlower(a);
  2024. #endif
  2025.  
  2026.     /* For characters below 128 use locale sensitive tolower(). */
  2027.     if (a < 128)
  2028.     return TOLOWER_LOC(a);
  2029.  
  2030.     /* For any other characters use the above mapping table. */
  2031.     return utf_convert(a, toLower, sizeof(toLower));
  2032. }
  2033.  
  2034.     int
  2035. utf_isupper(a)
  2036.     int        a;
  2037. {
  2038.     return (utf_tolower(a) != a);
  2039. }
  2040.  
  2041. /*
  2042.  * Version of strnicmp() that handles multi-byte characters.
  2043.  * Needed for Big5, Sjift-JIS and UTF-8 encoding.  Other DBCS encodings can
  2044.  * probably use strnicmp(), because there are no ASCII characters in the
  2045.  * second byte.
  2046.  * Returns zero if s1 and s2 are equal (ignoring case), the difference between
  2047.  * two characters otherwise.
  2048.  */
  2049.     int
  2050. mb_strnicmp(s1, s2, n)
  2051.     char_u    *s1, *s2;
  2052.     int        n;
  2053. {
  2054.     int        i, j, l;
  2055.     int        cdiff;
  2056.  
  2057.     for (i = 0; i < n; i += l)
  2058.     {
  2059.     if (s1[i] == NUL && s2[i] == NUL)   /* both strings end */
  2060.         return 0;
  2061.     if (enc_utf8)
  2062.     {
  2063.         l = utf_byte2len(s1[i]);
  2064.         if (l > n - i)
  2065.         l = n - i;            /* incomplete character */
  2066.         /* Check directly first, it's faster. */
  2067.         for (j = 0; j < l; ++j)
  2068.         if (s1[i + j] != s2[i + j])
  2069.             break;
  2070.         if (j < l)
  2071.         {
  2072.         /* If one of the two characters is incomplete return -1. */
  2073.         if (i + utf_byte2len(s1[i]) > n || i + utf_byte2len(s2[i]) > n)
  2074.             return -1;
  2075.         cdiff = utf_fold(utf_ptr2char(s1 + i))
  2076.                          - utf_fold(utf_ptr2char(s2 + i));
  2077.         if (cdiff != 0)
  2078.             return cdiff;
  2079.         }
  2080.     }
  2081.     else
  2082.     {
  2083.         l = (*mb_ptr2len_check)(s1 + i);
  2084.         if (l <= 1)
  2085.         {
  2086.         /* Single byte: first check normally, then with ignore case. */
  2087.         if (s1[i] != s2[i])
  2088.         {
  2089.             cdiff = TOLOWER_LOC(s1[i]) - TOLOWER_LOC(s2[i]);
  2090.             if (cdiff != 0)
  2091.             return cdiff;
  2092.         }
  2093.         }
  2094.         else
  2095.         {
  2096.         /* For non-Unicode multi-byte don't ignore case. */
  2097.         if (l > n - i)
  2098.             l = n - i;
  2099.         cdiff = STRNCMP(s1 + i, s2 + i, l);
  2100.         if (cdiff != 0)
  2101.             return cdiff;
  2102.         }
  2103.     }
  2104.     }
  2105.     return 0;
  2106. }
  2107.  
  2108. /*
  2109.  * "g8": show bytes of the UTF-8 char under the cursor.  Doesn't matter what
  2110.  * 'encoding' has been set to.
  2111.  */
  2112.     void
  2113. show_utf8()
  2114. {
  2115.     int        len;
  2116.     char_u    *line;
  2117.     int        clen;
  2118.     int        i;
  2119.  
  2120.     /* Get the byte length of the char under the cursor, including composing
  2121.      * characters. */
  2122.     line = ml_get_cursor();
  2123.     len = utfc_ptr2len_check(line);
  2124.     if (len == 0)
  2125.     {
  2126.     MSG("NUL");
  2127.     return;
  2128.     }
  2129.  
  2130.     IObuff[0] = NUL;
  2131.     clen = 0;
  2132.     for (i = 0; i < len; ++i)
  2133.     {
  2134.     if (clen == 0)
  2135.     {
  2136.         /* start of (composing) character, get its length */
  2137.         if (i > 0)
  2138.         STRCAT(IObuff, "+ ");
  2139.         clen = utf_ptr2len_check(line + i);
  2140.     }
  2141.     sprintf((char *)IObuff + STRLEN(IObuff), "%02x ", line[i]);
  2142.     --clen;
  2143.     }
  2144.  
  2145.     msg(IObuff);
  2146. }
  2147.  
  2148. /*
  2149.  * mb_head_off() function pointer.
  2150.  * Return offset from "p" to the first byte of the character it points into.
  2151.  * Returns 0 when already at the first byte of a character.
  2152.  */
  2153. /*ARGSUSED*/
  2154.     int
  2155. latin_head_off(base, p)
  2156.     char_u    *base;
  2157.     char_u    *p;
  2158. {
  2159.     return 0;
  2160. }
  2161.  
  2162.     int
  2163. dbcs_head_off(base, p)
  2164.     char_u    *base;
  2165.     char_u    *p;
  2166. {
  2167.     char_u    *q;
  2168.  
  2169.     /* It can't be a trailing byte when not using DBCS, at the start of the
  2170.      * string or the previous byte can't start a double-byte. */
  2171.     if (p <= base || MB_BYTE2LEN(p[-1]) == 1)
  2172.     return 0;
  2173.  
  2174.     /* This is slow: need to start at the base and go forward until the
  2175.      * byte we are looking for.  Return 1 when we went past it, 0 otherwise. */
  2176.     q = base;
  2177.     while (q < p)
  2178.     q += dbcs_ptr2len_check(q);
  2179.     return (q == p) ? 0 : 1;
  2180. }
  2181.  
  2182. #if defined(FEAT_CLIPBOARD) || defined(FEAT_GUI) || defined(FEAT_RIGHTLEFT) \
  2183.     || defined(PROTO)
  2184. /*
  2185.  * Special version of dbcs_head_off() that works for ScreenLines[], where
  2186.  * single-width DBCS_JPNU characters are stored separately.
  2187.  */
  2188.     int
  2189. dbcs_screen_head_off(base, p)
  2190.     char_u    *base;
  2191.     char_u    *p;
  2192. {
  2193.     char_u    *q;
  2194.  
  2195.     /* It can't be a trailing byte when not using DBCS, at the start of the
  2196.      * string or the previous byte can't start a double-byte.
  2197.      * For euc-jp an 0x8e byte in the previous cell always means we have a
  2198.      * lead byte in the current cell. */
  2199.     if (p <= base
  2200.         || (enc_dbcs == DBCS_JPNU && p[-1] == 0x8e)
  2201.         || MB_BYTE2LEN(p[-1]) == 1)
  2202.     return 0;
  2203.  
  2204.     /* This is slow: need to start at the base and go forward until the
  2205.      * byte we are looking for.  Return 1 when we went past it, 0 otherwise.
  2206.      * For DBCS_JPNU look out for 0x8e, which means the second byte is not
  2207.      * stored as the next byte. */
  2208.     q = base;
  2209.     while (q < p)
  2210.     {
  2211.     if (enc_dbcs == DBCS_JPNU && *q == 0x8e)
  2212.         ++q;
  2213.     else
  2214.         q += dbcs_ptr2len_check(q);
  2215.     }
  2216.     return (q == p) ? 0 : 1;
  2217. }
  2218. #endif
  2219.  
  2220.     int
  2221. utf_head_off(base, p)
  2222.     char_u    *base;
  2223.     char_u    *p;
  2224. {
  2225.     char_u    *q;
  2226.     char_u    *s;
  2227.     int        c;
  2228. #ifdef FEAT_ARABIC
  2229.     char_u    *j;
  2230. #endif
  2231.  
  2232.     if (*p < 0x80)        /* be quick for ASCII */
  2233.     return 0;
  2234.  
  2235.     /* Skip backwards over trailing bytes: 10xx.xxxx
  2236.      * Skip backwards again if on a composing char. */
  2237.     for (q = p; ; --q)
  2238.     {
  2239.     /* Move s to the last byte of this char. */
  2240.     for (s = q; (s[1] & 0xc0) == 0x80; ++s)
  2241.         ;
  2242.     /* Move q to the first byte of this char. */
  2243.     while (q > base && (*q & 0xc0) == 0x80)
  2244.         --q;
  2245.     /* Check for illegal sequence. Do allow an illegal byte after where we
  2246.      * started. */
  2247.     if (utf8len_tab[*q] != (int)(s - q + 1)
  2248.                        && utf8len_tab[*q] != (int)(p - q + 1))
  2249.         return 0;
  2250.  
  2251.     if (q <= base)
  2252.         break;
  2253.  
  2254.     c = utf_ptr2char(q);
  2255.     if (utf_iscomposing(c))
  2256.         continue;
  2257.  
  2258. #ifdef FEAT_ARABIC
  2259.     if (arabic_maycombine(c))
  2260.     {
  2261.         /* Advance to get a sneak-peak at the next char */
  2262.         j = q;
  2263.         --j;
  2264.         /* Move j to the first byte of this char. */
  2265.         while (j > base && (*j & 0xc0) == 0x80)
  2266.         --j;
  2267.         if (arabic_combine(utf_ptr2char(j), c))
  2268.         continue;
  2269.     }
  2270. #endif
  2271.     break;
  2272.     }
  2273.  
  2274.     return (int)(p - q);
  2275. }
  2276.  
  2277. /*
  2278.  * Return the offset from "p" to the first byte of a character.  When "p" is
  2279.  * at the start of a character 0 is returned, otherwise the offset to the next
  2280.  * character.  Can start anywhere in a stream of bytes.
  2281.  */
  2282.     int
  2283. mb_off_next(base, p)
  2284.     char_u    *base;
  2285.     char_u    *p;
  2286. {
  2287.     int        i;
  2288.     int        j;
  2289.  
  2290.     if (enc_utf8)
  2291.     {
  2292.     if (*p < 0x80)        /* be quick for ASCII */
  2293.         return 0;
  2294.  
  2295.     /* Find the next character that isn't 10xx.xxxx */
  2296.     for (i = 0; (p[i] & 0xc0) == 0x80; ++i)
  2297.         ;
  2298.     if (i > 0)
  2299.     {
  2300.         /* Check for illegal sequence. */
  2301.         for (j = 0; p - j > base; ++j)
  2302.         if ((p[-j] & 0xc0) != 0x80)
  2303.             break;
  2304.         if (utf8len_tab[p[-j]] != i + j)
  2305.         return 0;
  2306.     }
  2307.     return i;
  2308.     }
  2309.  
  2310.     /* Only need to check if we're on a trail byte, it doesn't matter if we
  2311.      * want the offset to the next or current character. */
  2312.     return (*mb_head_off)(base, p);
  2313. }
  2314.  
  2315. /*
  2316.  * Return the offset from "p" to the last byte of the character it points
  2317.  * into.  Can start anywhere in a stream of bytes.
  2318.  */
  2319.     int
  2320. mb_tail_off(base, p)
  2321.     char_u    *base;
  2322.     char_u    *p;
  2323. {
  2324.     int        i;
  2325.     int        j;
  2326.  
  2327.     if (*p == NUL)
  2328.     return 0;
  2329.  
  2330.     if (enc_utf8)
  2331.     {
  2332.     /* Find the last character that is 10xx.xxxx */
  2333.     for (i = 0; (p[i + 1] & 0xc0) == 0x80; ++i)
  2334.         ;
  2335.     /* Check for illegal sequence. */
  2336.     for (j = 0; p - j > base; ++j)
  2337.         if ((p[-j] & 0xc0) != 0x80)
  2338.         break;
  2339.     if (utf8len_tab[p[-j]] != i + j + 1)
  2340.         return 0;
  2341.     return i;
  2342.     }
  2343.  
  2344.     /* It can't be the first byte if a double-byte when not using DBCS, at the
  2345.      * end of the string or the byte can't start a double-byte. */
  2346.     if (enc_dbcs == 0 || p[1] == NUL || MB_BYTE2LEN(*p) == 1)
  2347.     return 0;
  2348.  
  2349.     /* Return 1 when on the lead byte, 0 when on the tail byte. */
  2350.     return 1 - dbcs_head_off(base, p);
  2351. }
  2352.  
  2353. #if defined(FEAT_GUI) || defined(PROTO)
  2354. /*
  2355.  * Special version of mb_tail_off() for use in ScreenLines[].
  2356.  */
  2357.     int
  2358. dbcs_screen_tail_off(base, p)
  2359.     char_u    *base;
  2360.     char_u    *p;
  2361. {
  2362.     /* It can't be the first byte if a double-byte when not using DBCS, at the
  2363.      * end of the string or the byte can't start a double-byte.
  2364.      * For euc-jp an 0x8e byte always means we have a lead byte in the current
  2365.      * cell. */
  2366.     if (*p == NUL || p[1] == NUL
  2367.         || (enc_dbcs == DBCS_JPNU && *p == 0x8e)
  2368.         || MB_BYTE2LEN(*p) == 1)
  2369.     return 0;
  2370.  
  2371.     /* Return 1 when on the lead byte, 0 when on the tail byte. */
  2372.     return 1 - dbcs_screen_head_off(base, p);
  2373. }
  2374. #endif
  2375.  
  2376. /*
  2377.  * If the cursor moves on an trail byte, set the cursor on the lead byte.
  2378.  * Thus it moves left if necessary.
  2379.  * Return TRUE when the cursor was adjusted.
  2380.  */
  2381.     void
  2382. mb_adjust_cursor()
  2383. {
  2384.     mb_adjustpos(&curwin->w_cursor);
  2385. }
  2386.  
  2387. /*
  2388.  * Adjust position "*lp" to point to the first byte of a multi-byte character.
  2389.  * If it points to a tail byte it's moved backwards to the head byte.
  2390.  */
  2391.     void
  2392. mb_adjustpos(lp)
  2393.     pos_T    *lp;
  2394. {
  2395.     char_u    *p;
  2396.  
  2397.     if (lp->col > 0
  2398. #ifdef FEAT_VIRTUALEDIT
  2399.         || lp->coladd > 1
  2400. #endif
  2401.         )
  2402.     {
  2403.     p = ml_get(lp->lnum);
  2404.     lp->col -= (*mb_head_off)(p, p + lp->col);
  2405. #ifdef FEAT_VIRTUALEDIT
  2406.     /* Reset "coladd" when the cursor would be on the right half of a
  2407.      * double-wide character. */
  2408.     if (lp->coladd == 1
  2409.         && p[lp->col] != TAB
  2410.         && vim_isprintc((*mb_ptr2char)(p + lp->col))
  2411.         && ptr2cells(p + lp->col) > 1)
  2412.         lp->coladd = 0;
  2413. #endif
  2414.     }
  2415. }
  2416.  
  2417. /*
  2418.  * Return a pointer to the character before "*p", if there is one.
  2419.  */
  2420.     char_u *
  2421. mb_prevptr(line, p)
  2422.     char_u *line;    /* start of the string */
  2423.     char_u *p;
  2424. {
  2425.     if (p > line)
  2426.     p = p - (*mb_head_off)(line, p - 1) - 1;
  2427.     return p;
  2428. }
  2429.  
  2430. /*
  2431.  * Return the character length of "str".  multi-byte characters counts as one.
  2432.  */
  2433.     int
  2434. mb_charlen(str)
  2435.     char_u    *str;
  2436. {
  2437.     int count;
  2438.  
  2439.     if (str == NULL)
  2440.     return 0;
  2441.  
  2442.     for (count = 0; *str != NUL; count++)
  2443.     str += (*mb_ptr2len_check)(str);
  2444.  
  2445.     return count;
  2446. }
  2447.  
  2448. /*
  2449.  * Decrement position "lp" by one character, taking care of multi-byte chars.
  2450.  */
  2451.     int
  2452. mb_dec(lp)
  2453.     pos_T    *lp;
  2454. {
  2455.     if (lp->col > 0)        /* still within line */
  2456.     {
  2457.     --lp->col;
  2458.     mb_adjustpos(lp);
  2459.     return 0;
  2460.     }
  2461.     if (lp->lnum > 1)        /* there is a prior line */
  2462.     {
  2463.     lp->lnum--;
  2464.     lp->col = (colnr_T)STRLEN(ml_get(lp->lnum));
  2465.     mb_adjustpos(lp);
  2466.     return 1;
  2467.     }
  2468.     return -1;            /* at start of file */
  2469. }
  2470.  
  2471. /*
  2472.  * Try to un-escape a multi-byte character.
  2473.  * Used for the "to" and "from" part of a mapping.
  2474.  * Return the un-escaped string if it is a multi-byte character, and advance
  2475.  * "pp" to just after the bytes that formed it.
  2476.  * Return NULL if no multi-byte char was found.
  2477.  */
  2478.     char_u *
  2479. mb_unescape(pp)
  2480.     char_u **pp;
  2481. {
  2482.     static char_u    buf[MB_MAXBYTES + 1];
  2483.     int            n, m = 0;
  2484.     char_u        *str = *pp;
  2485.  
  2486.     /* Must translate K_SPECIAL KS_SPECIAL KE_FILLER to K_SPECIAL and CSI
  2487.      * KS_EXTRA KE_CSI to CSI. */
  2488.     for (n = 0; str[n] != NUL && m <= MB_MAXBYTES; ++n)
  2489.     {
  2490.     if (str[n] == K_SPECIAL
  2491.         && str[n + 1] == KS_SPECIAL
  2492.         && str[n + 2] == KE_FILLER)
  2493.     {
  2494.         buf[m++] = K_SPECIAL;
  2495.         n += 2;
  2496.     }
  2497. # ifdef FEAT_GUI
  2498.     else if (str[n] == CSI
  2499.         && str[n + 1] == KS_EXTRA
  2500.         && str[n + 2] == (int)KE_CSI)
  2501.     {
  2502.         buf[m++] = CSI;
  2503.         n += 2;
  2504.     }
  2505. # endif
  2506.     else if (str[n] == K_SPECIAL
  2507. # ifdef FEAT_GUI
  2508.         || str[n] == CSI
  2509. # endif
  2510.         )
  2511.         break;        /* a special key can't be a multibyte char */
  2512.     else
  2513.         buf[m++] = str[n];
  2514.     buf[m] = NUL;
  2515.  
  2516.     /* Return a multi-byte character if it's found.  An illegal sequence
  2517.      * will result in a 1 here. */
  2518.     if ((*mb_ptr2len_check)(buf) > 1)
  2519.     {
  2520.         *pp = str + n + 1;
  2521.         return buf;
  2522.     }
  2523.     }
  2524.     return NULL;
  2525. }
  2526.  
  2527. /*
  2528.  * Return TRUE if the character at "row"/"col" on the screen is the left side
  2529.  * of a double-width character.
  2530.  * Caller must make sure "row" and "col" are not invalid!
  2531.  */
  2532.     int
  2533. mb_lefthalve(row, col)
  2534.     int        row;
  2535.     int        col;
  2536. {
  2537. #ifdef FEAT_HANGULIN
  2538.     if (composing_hangul)
  2539.     return TRUE;
  2540. #endif
  2541.     if (enc_dbcs != 0)
  2542.     return dbcs_off2cells(LineOffset[row] + col) > 1;
  2543.     if (enc_utf8)
  2544.     return (col + 1 < Columns
  2545.         && ScreenLines[LineOffset[row] + col + 1] == 0);
  2546.     return FALSE;
  2547. }
  2548.  
  2549. # if defined(FEAT_CLIPBOARD) || defined(FEAT_GUI) || defined(FEAT_RIGHTLEFT) \
  2550.     || defined(PROTO)
  2551. /*
  2552.  * Correct a position on the screen, if it's the right halve of a double-wide
  2553.  * char move it to the left halve.  Returns the corrected column.
  2554.  */
  2555.     int
  2556. mb_fix_col(col, row)
  2557.     int        col;
  2558.     int        row;
  2559. {
  2560.     col = check_col(col);
  2561.     row = check_row(row);
  2562.     if (has_mbyte && ScreenLines != NULL && col > 0
  2563.         && ((enc_dbcs
  2564.             && ScreenLines[LineOffset[row] + col] != NUL
  2565.             && dbcs_screen_head_off(ScreenLines + LineOffset[row],
  2566.                      ScreenLines + LineOffset[row] + col))
  2567.         || (enc_utf8 && ScreenLines[LineOffset[row] + col] == 0)))
  2568.     --col;
  2569.     return col;
  2570. }
  2571. # endif
  2572. #endif
  2573.  
  2574. #if defined(FEAT_MBYTE) || defined(FEAT_POSTSCRIPT) || defined(PROTO)
  2575. static int enc_alias_search __ARGS((char_u *name));
  2576.  
  2577. /*
  2578.  * Skip the Vim specific head of a 'encoding' name.
  2579.  */
  2580.     char_u *
  2581. enc_skip(p)
  2582.     char_u    *p;
  2583. {
  2584.     if (STRNCMP(p, "2byte-", 6) == 0)
  2585.     return p + 6;
  2586.     if (STRNCMP(p, "8bit-", 5) == 0)
  2587.     return p + 5;
  2588.     return p;
  2589. }
  2590.  
  2591. /*
  2592.  * Find the canonical name for encoding "enc".
  2593.  * When the name isn't recognized, returns "enc" itself, but with all lower
  2594.  * case characters and '_' replaced with '-'.
  2595.  * Returns an allocated string.  NULL for out-of-memory.
  2596.  */
  2597.     char_u *
  2598. enc_canonize(enc)
  2599.     char_u    *enc;
  2600. {
  2601.     char_u    *r;
  2602.     char_u    *p, *s;
  2603.     int        i;
  2604.  
  2605.     /* copy "enc" to allocted memory, with room for two '-' */
  2606.     r = alloc((unsigned)(STRLEN(enc) + 3));
  2607.     if (r != NULL)
  2608.     {
  2609.     /* Make it all lower case and replace '_' with '-'. */
  2610.     p = r;
  2611.     for (s = enc; *s != NUL; ++s)
  2612.     {
  2613.         if (*s == '_')
  2614.         *p++ = '-';
  2615.         else
  2616.         *p++ = TOLOWER_ASC(*s);
  2617.     }
  2618.     *p = NUL;
  2619.  
  2620.     /* Skip "2byte-" and "8bit-". */
  2621.     p = enc_skip(r);
  2622.  
  2623.     /* "iso8859" -> "iso-8859" */
  2624.     if (STRNCMP(p, "iso8859", 7) == 0)
  2625.     {
  2626.         mch_memmove(p + 4, p + 3, STRLEN(p + 2));
  2627.         p[3] = '-';
  2628.     }
  2629.  
  2630.     /* "iso-8859n" -> "iso-8859-n" */
  2631.     if (STRNCMP(p, "iso-8859", 8) == 0 && p[8] != '-')
  2632.     {
  2633.         mch_memmove(p + 9, p + 8, STRLEN(p + 7));
  2634.         p[8] = '-';
  2635.     }
  2636.  
  2637.     /* "latin-N" -> "latinN" */
  2638.     if (STRNCMP(p, "latin-", 6) == 0)
  2639.         mch_memmove(p + 5, p + 6, STRLEN(p + 5));
  2640.  
  2641.     if (enc_canon_search(p) >= 0)
  2642.     {
  2643.         /* canonical name can be used unmodified */
  2644.         if (p != r)
  2645.         mch_memmove(r, p, STRLEN(p) + 1);
  2646.     }
  2647.     else if ((i = enc_alias_search(p)) >= 0)
  2648.     {
  2649.         /* alias recognized, get canonical name */
  2650.         vim_free(r);
  2651.         r = vim_strsave((char_u *)enc_canon_table[i].name);
  2652.     }
  2653.     }
  2654.     return r;
  2655. }
  2656.  
  2657. /*
  2658.  * Search for an encoding alias of "name".
  2659.  * Returns -1 when not found.
  2660.  */
  2661.     static int
  2662. enc_alias_search(name)
  2663.     char_u    *name;
  2664. {
  2665.     int        i;
  2666.  
  2667.     for (i = 0; enc_alias_table[i].name != NULL; ++i)
  2668.     if (STRCMP(name, enc_alias_table[i].name) == 0)
  2669.         return enc_alias_table[i].canon;
  2670.     return -1;
  2671. }
  2672. #endif
  2673.  
  2674. #if defined(FEAT_MBYTE) || defined(PROTO)
  2675.  
  2676. #ifdef HAVE_LANGINFO_H
  2677. # include <langinfo.h>
  2678. #endif
  2679.  
  2680. /*
  2681.  * Get the canonicalized encoding of the current locale.
  2682.  * Returns an allocated string when successful, NULL when not.
  2683.  */
  2684.     char_u *
  2685. enc_locale()
  2686. {
  2687. #ifndef WIN3264
  2688.     char    *s;
  2689.     char    *p;
  2690.     int        i;
  2691. #endif
  2692.     char    buf[50];
  2693. #ifdef WIN3264
  2694.     long    acp = GetACP();
  2695.  
  2696.     if (acp == 1200)
  2697.     STRCPY(buf, "ucs-2le");
  2698.     else if (acp == 1252)
  2699.     STRCPY(buf, "latin1");
  2700.     else
  2701.     sprintf(buf, "cp%ld", acp);
  2702. #else
  2703. # ifdef HAVE_NL_LANGINFO_CODESET
  2704.     if ((s = nl_langinfo(CODESET)) == NULL || *s == NUL)
  2705. # endif
  2706. # if defined(HAVE_LOCALE_H) || defined(X_LOCALE)
  2707.     if ((s = setlocale(LC_CTYPE, NULL)) == NULL || *s == NUL)
  2708. # endif
  2709.         if ((s = getenv("LC_ALL")) == NULL || *s == NUL)
  2710.         if ((s = getenv("LC_CTYPE")) == NULL || *s == NUL)
  2711.             s = getenv("LANG");
  2712.  
  2713.     if (s == NULL || *s == NUL)
  2714.     return FAIL;
  2715.  
  2716.     /* The most generic locale format is:
  2717.      * language[_territory][.codeset][@modifier][+special][,[sponsor][_revision]]
  2718.      * If there is a '.' remove the part before it.
  2719.      * if there is something after the codeset, remove it.
  2720.      * Make the name lowercase and replace '_' with '-'.
  2721.      * Exception: "ja_JP.EUC" == "euc-jp", "zh_CN.EUC" = "euc-cn",
  2722.      * "ko_KR.EUC" == "euc-kr"
  2723.      */
  2724.     if ((p = (char *)vim_strchr((char_u *)s, '.')) != NULL)
  2725.     {
  2726.     if (p > s + 2 && STRNICMP(p + 1, "EUC", 3) == 0
  2727.             && !isalnum((int)p[4]) && p[4] != '-' && p[-3] == '_')
  2728.     {
  2729.         /* copy "XY.EUC" to "euc-XY" to buf[10] */
  2730.         STRCPY(buf + 10, "euc-");
  2731.         buf[14] = p[-2];
  2732.         buf[15] = p[-1];
  2733.         buf[16] = 0;
  2734.         s = buf + 10;
  2735.     }
  2736.     else
  2737.         s = p + 1;
  2738.     }
  2739.     for (i = 0; s[i] != NUL && i < sizeof(buf) - 1; ++i)
  2740.     {
  2741.     if (s[i] == '_' || s[i] == '-')
  2742.         buf[i] = '-';
  2743.     else if (isalnum((int)s[i]))
  2744.         buf[i] = TOLOWER_ASC(s[i]);
  2745.     else
  2746.         break;
  2747.     }
  2748.     buf[i] = NUL;
  2749. #endif
  2750.  
  2751.     return enc_canonize((char_u *)buf);
  2752. }
  2753.  
  2754. #if defined(WIN3264) || defined(PROTO)
  2755. /*
  2756.  * Convert an encoding name to an MS-Windows codepage.
  2757.  * Returns zero if no codepage can be figured out.
  2758.  */
  2759.     int
  2760. encname2codepage(name)
  2761.     char_u    *name;
  2762. {
  2763.     int        cp;
  2764.     char_u    *p = name;
  2765.     int        idx;
  2766.  
  2767.     if (STRNCMP(p, "8bit-", 5) == 0)
  2768.     p += 5;
  2769.     else if (STRNCMP(p_enc, "2byte-", 6) == 0)
  2770.     p += 6;
  2771.  
  2772.     if (p[0] == 'c' && p[1] == 'p')
  2773.     cp = atoi(p + 2);
  2774.     else if ((idx = enc_canon_search(p)) >= 0)
  2775.     cp = enc_canon_table[idx].codepage;
  2776.     if (IsValidCodePage(cp))
  2777.     return cp;
  2778.     return 0;
  2779. }
  2780. #endif
  2781.  
  2782. # if defined(USE_ICONV) || defined(PROTO)
  2783.  
  2784. static char_u *iconv_string __ARGS((iconv_t fd, char_u *str, int slen));
  2785.  
  2786. /*
  2787.  * Call iconv_open() with a check if iconv() works properly (there are broken
  2788.  * versions).
  2789.  * Returns (void *)-1 if failed.
  2790.  * (should return iconv_t, but that causes problems with prototypes).
  2791.  */
  2792.     void *
  2793. my_iconv_open(to, from)
  2794.     char_u    *to;
  2795.     char_u    *from;
  2796. {
  2797.     iconv_t    fd;
  2798. #define ICONV_TESTLEN 400
  2799.     char_u    tobuf[ICONV_TESTLEN];
  2800.     char    *p;
  2801.     size_t    tolen;
  2802.     static int    iconv_ok = -1;
  2803.  
  2804.     if (iconv_ok == FALSE)
  2805.     return (void *)-1;    /* detected a broken iconv() previously */
  2806.  
  2807. #ifdef DYNAMIC_ICONV
  2808.     /* Check if the iconv.dll can be found. */
  2809.     if (!iconv_enabled(TRUE))
  2810.     return (void *)-1;
  2811. #endif
  2812.  
  2813.     fd = iconv_open((char *)enc_skip(to), (char *)enc_skip(from));
  2814.  
  2815.     if (fd != (iconv_t)-1 && iconv_ok == -1)
  2816.     {
  2817.     /*
  2818.      * Do a dummy iconv() call to check if it actually works.  There is a
  2819.      * version of iconv() on Linux that is broken.  We can't ignore it,
  2820.      * because it's wide-spread.  The symptoms are that after outputting
  2821.      * the initial shift state the "to" pointer is NULL and conversion
  2822.      * stops for no apparent reason after about 8160 characters.
  2823.      */
  2824.     p = (char *)tobuf;
  2825.     tolen = ICONV_TESTLEN;
  2826.     (void)iconv(fd, NULL, NULL, &p, &tolen);
  2827.     if (p == NULL)
  2828.     {
  2829.         iconv_ok = FALSE;
  2830.         iconv_close(fd);
  2831.         fd = (iconv_t)-1;
  2832.     }
  2833.     else
  2834.         iconv_ok = TRUE;
  2835.     }
  2836.  
  2837.     return (void *)fd;
  2838. }
  2839.  
  2840. /*
  2841.  * Convert the string "str[slen]" with iconv().
  2842.  * Returns the converted string in allocated memory.  NULL for an error.
  2843.  */
  2844.     static char_u *
  2845. iconv_string(fd, str, slen)
  2846.     iconv_t    fd;
  2847.     char_u    *str;
  2848.     int        slen;
  2849. {
  2850.     const char    *from;
  2851.     size_t    fromlen;
  2852.     char    *to;
  2853.     size_t    tolen;
  2854.     size_t    len = 0;
  2855.     size_t    done = 0;
  2856.     char_u    *result = NULL;
  2857.     char_u    *p;
  2858.     int        l;
  2859.  
  2860.     from = (char *)str;
  2861.     fromlen = slen;
  2862.     for (;;)
  2863.     {
  2864.     if (len == 0 || ICONV_ERRNO == ICONV_E2BIG)
  2865.     {
  2866.         /* Allocate enough room for most conversions.  When re-allocating
  2867.          * increase the buffer size. */
  2868.         len = len + fromlen * 2 + 40;
  2869.         p = alloc((unsigned)len);
  2870.         if (p != NULL && done > 0)
  2871.         mch_memmove(p, result, done);
  2872.         vim_free(result);
  2873.         result = p;
  2874.         if (result == NULL)    /* out of memory */
  2875.         break;
  2876.     }
  2877.  
  2878.     to = (char *)result + done;
  2879.     tolen = len - done - 2;
  2880.     if (iconv(fd, &from, &fromlen, &to, &tolen) != (size_t)-1)
  2881.     {
  2882.         /* Finished, append a NUL. */
  2883.         *to = NUL;
  2884.         break;
  2885.     }
  2886.     /* Check both ICONV_EILSEQ and EILSEQ, because the dynamically loaded
  2887.      * iconv library may use one of them. */
  2888.     if (ICONV_ERRNO == ICONV_EILSEQ || ICONV_ERRNO == EILSEQ)
  2889.     {
  2890.         /* Can't convert: insert a '?' and skip a character.  This assumes
  2891.          * conversion from 'encoding' to something else.  In other
  2892.          * situations we don't know what to skip anyway. */
  2893.         *to++ = '?';
  2894.         if ((*mb_ptr2cells)((char_u *)from) > 1)
  2895.         *to++ = '?';
  2896.         l = (*mb_ptr2len_check)((char_u *)from);
  2897.         from += l;
  2898.         fromlen -= l;
  2899.     }
  2900.     else if (ICONV_ERRNO != ICONV_E2BIG)
  2901.     {
  2902.         /* conversion failed */
  2903.         vim_free(result);
  2904.         result = NULL;
  2905.         break;
  2906.     }
  2907.     /* Not enough room or skipping illegal sequence. */
  2908.     done = to - (char *)result;
  2909.     }
  2910.     return result;
  2911. }
  2912.  
  2913. #  if defined(DYNAMIC_ICONV) || defined(PROTO)
  2914. /*
  2915.  * Dynamically load the "iconv.dll" on Win32.
  2916.  */
  2917.  
  2918. #ifndef DYNAMIC_ICONV        /* just generating prototypes */
  2919. # define HINSTANCE int
  2920. #endif
  2921. HINSTANCE hIconvDLL = 0;
  2922. HINSTANCE hMsvcrtDLL = 0;
  2923.  
  2924. #  ifndef DYNAMIC_ICONV_DLL
  2925. #   define DYNAMIC_ICONV_DLL "iconv.dll"
  2926. #   define DYNAMIC_ICONV_DLL_ALT "libiconv.dll"
  2927. #  endif
  2928. #  ifndef DYNAMIC_MSVCRT_DLL
  2929. #   define DYNAMIC_MSVCRT_DLL "msvcrt.dll"
  2930. #  endif
  2931.  
  2932. /*
  2933.  * Try opening the iconv.dll and return TRUE if iconv() can be used.
  2934.  */
  2935.     int
  2936. iconv_enabled(verbose)
  2937.     int        verbose;
  2938. {
  2939.     if (hIconvDLL != 0 && hMsvcrtDLL != 0)
  2940.     return TRUE;
  2941.     hIconvDLL = LoadLibrary(DYNAMIC_ICONV_DLL);
  2942.     if (hIconvDLL == 0)        /* sometimes it's called libiconv.dll */
  2943.     hIconvDLL = LoadLibrary(DYNAMIC_ICONV_DLL_ALT);
  2944.     if (hIconvDLL != 0)
  2945.     hMsvcrtDLL = LoadLibrary(DYNAMIC_MSVCRT_DLL);
  2946.     if (hIconvDLL == 0 || hMsvcrtDLL == 0)
  2947.     {
  2948.     /* Only give the message when 'verbose' is set, otherwise it might be
  2949.      * done whenever a conversion is attempted. */
  2950.     if (verbose && p_verbose > 0)
  2951.         EMSG2(_(e_loadlib),
  2952.             hIconvDLL == 0 ? DYNAMIC_ICONV_DLL : DYNAMIC_MSVCRT_DLL);
  2953.     iconv_end();
  2954.     return FALSE;
  2955.     }
  2956.  
  2957.     *((FARPROC*)&iconv)        = GetProcAddress(hIconvDLL, "libiconv");
  2958.     *((FARPROC*)&iconv_open)    = GetProcAddress(hIconvDLL, "libiconv_open");
  2959.     *((FARPROC*)&iconv_close)    = GetProcAddress(hIconvDLL, "libiconv_close");
  2960.     *((FARPROC*)&iconvctl)    = GetProcAddress(hIconvDLL, "libiconvctl");
  2961.     *((FARPROC*)&iconv_errno)    = GetProcAddress(hMsvcrtDLL, "_errno");
  2962.     if (iconv == NULL || iconv_open == NULL || iconv_close == NULL
  2963.         || iconvctl == NULL || iconv_errno == NULL)
  2964.     {
  2965.     iconv_end();
  2966.     if (verbose && p_verbose > 0)
  2967.         EMSG2(_(e_loadfunc), "for libiconv");
  2968.     return FALSE;
  2969.     }
  2970.     return TRUE;
  2971. }
  2972.  
  2973.     void
  2974. iconv_end()
  2975. {
  2976.     /* Don't use iconv() when inputting or outputting characters. */
  2977.     if (input_conv.vc_type == CONV_ICONV)
  2978.     convert_setup(&input_conv, NULL, NULL);
  2979.     if (output_conv.vc_type == CONV_ICONV)
  2980.     convert_setup(&output_conv, NULL, NULL);
  2981.  
  2982.     if (hIconvDLL != 0)
  2983.     FreeLibrary(hIconvDLL);
  2984.     if (hMsvcrtDLL != 0)
  2985.     FreeLibrary(hMsvcrtDLL);
  2986.     hIconvDLL = 0;
  2987.     hMsvcrtDLL = 0;
  2988. }
  2989. #  endif /* DYNAMIC_ICONV */
  2990. # endif /* USE_ICONV */
  2991.  
  2992. #endif /* FEAT_MBYTE */
  2993.  
  2994. #if defined(FEAT_XIM) || defined(PROTO)
  2995.  
  2996. # if defined(HAVE_GTK2) && !defined(PROTO)
  2997.  
  2998. static int im_is_active           = FALSE;    /* IM is enabled for current mode    */
  2999. static int im_preedit_cursor   = 0;    /* cursor offset in characters       */
  3000. static int im_preedit_trailing = 0;    /* number of characters after cursor */
  3001.  
  3002. static unsigned long im_commit_handler_id  = 0;
  3003. static unsigned int  im_activatekey_keyval = GDK_VoidSymbol;
  3004. static unsigned int  im_activatekey_state  = 0;
  3005.  
  3006.     void
  3007. im_set_active(int active)
  3008. {
  3009.     int was_active;
  3010.  
  3011.     was_active = !!im_is_active;
  3012.     im_is_active = (active && !p_imdisable);
  3013.  
  3014.     if (im_is_active != was_active)
  3015.     xim_reset();
  3016. }
  3017.  
  3018.     void
  3019. xim_set_focus(int focus)
  3020. {
  3021.     if (xic != NULL)
  3022.     {
  3023.     if (focus)
  3024.         gtk_im_context_focus_in(xic);
  3025.     else
  3026.         gtk_im_context_focus_out(xic);
  3027.     }
  3028. }
  3029.  
  3030.     void
  3031. im_set_position(int row, int col)
  3032. {
  3033.     if (xic != NULL)
  3034.     {
  3035.     GdkRectangle area;
  3036.  
  3037.     area.x = FILL_X(col);
  3038.     area.y = FILL_Y(row);
  3039.     area.width  = gui.char_width * (mb_lefthalve(row, col) ? 2 : 1);
  3040.     area.height = gui.char_height;
  3041.  
  3042.     gtk_im_context_set_cursor_location(xic, &area);
  3043.     }
  3044. }
  3045.  
  3046. #  if 0 || defined(PROTO) /* apparently only used in gui_x11.c */
  3047.     void
  3048. xim_set_preedit(void)
  3049. {
  3050.     im_set_position(gui.row, gui.col);
  3051. }
  3052. #  endif
  3053.  
  3054.     static void
  3055. im_add_to_input(char_u *str, int len)
  3056. {
  3057.     /* Convert from 'termencoding' (always "utf-8") to 'encoding' */
  3058.     if (input_conv.vc_type != CONV_NONE)
  3059.     {
  3060.     str = string_convert(&input_conv, str, &len);
  3061.     g_return_if_fail(str != NULL);
  3062.     }
  3063.  
  3064.     add_to_input_buf_csi(str, len);
  3065.  
  3066.     if (input_conv.vc_type != CONV_NONE)
  3067.     vim_free(str);
  3068.  
  3069.     if (p_mh) /* blank out the pointer if necessary */
  3070.     gui_mch_mousehide(TRUE);
  3071. }
  3072.  
  3073.     static void
  3074. im_delete_preedit(void)
  3075. {
  3076.     char_u bskey[]  = {CSI, 'k', 'b'};
  3077.     char_u delkey[] = {CSI, 'k', 'D'};
  3078.  
  3079.     if (State & NORMAL)
  3080.     {
  3081.     im_preedit_cursor = 0;
  3082.     return;
  3083.     }
  3084.     for (; im_preedit_cursor > 0; --im_preedit_cursor)
  3085.     add_to_input_buf(bskey, (int)sizeof(bskey));
  3086.  
  3087.     for (; im_preedit_trailing > 0; --im_preedit_trailing)
  3088.     add_to_input_buf(delkey, (int)sizeof(delkey));
  3089. }
  3090.  
  3091.     static void
  3092. im_correct_cursor(int num_move_back)
  3093. {
  3094.     char_u backkey[] = {CSI, 'k', 'l'};
  3095.  
  3096.     if (State & NORMAL)
  3097.     return;
  3098. #  ifdef FEAT_RIGHTLEFT
  3099.     if ((State & CMDLINE) == 0 && curwin != NULL && curwin->w_p_rl)
  3100.     backkey[2] = 'r';
  3101. #  endif
  3102.     for (; num_move_back > 0; --num_move_back)
  3103.     add_to_input_buf(backkey, (int)sizeof(backkey));
  3104. }
  3105.  
  3106. /*
  3107.  * Callback invoked when the user finished preediting.
  3108.  * Put the final string into the input buffer.
  3109.  */
  3110. /*ARGSUSED0*/
  3111.     static void
  3112. im_commit_cb(GtkIMContext *context, const gchar *str, gpointer data)
  3113. {
  3114.     /* The imhangul module doesn't reset the preedit string before
  3115.      * committing.  Call im_delete_preedit() to work around that. */
  3116.     im_delete_preedit();
  3117.  
  3118.     /* Indicate that preediting has finished */
  3119.     preedit_start_col = MAXCOL;
  3120.  
  3121.     im_add_to_input((char_u *)str, (int)strlen(str));
  3122.  
  3123.     if (gtk_main_level() > 0)
  3124.     gtk_main_quit();
  3125. }
  3126.  
  3127. /*
  3128.  * Callback invoked after start to the preedit.
  3129.  */
  3130. /*ARGSUSED*/
  3131.     static void
  3132. im_preedit_start_cb(GtkIMContext *context, gpointer data)
  3133. {
  3134.     im_is_active = TRUE;
  3135.     gui_update_cursor(TRUE, FALSE);
  3136. }
  3137. /*
  3138.  * Callback invoked after end to the preedit.
  3139.  */
  3140. /*ARGSUSED*/
  3141.     static void
  3142. im_preedit_end_cb(GtkIMContext *context, gpointer data)
  3143. {
  3144.     im_is_active = FALSE;
  3145.     gui_update_cursor(TRUE, FALSE);
  3146. }
  3147.  
  3148. /*
  3149.  * Callback invoked after changes to the preedit string.  If the preedit
  3150.  * string was empty before, remember the preedit start column so we know
  3151.  * where to apply feedback attributes.  Delete the previous preedit string
  3152.  * if there was one, save the new preedit cursor offset, and put the new
  3153.  * string into the input buffer.
  3154.  *
  3155.  * TODO: The pragmatic "put into input buffer" approach used here has
  3156.  *       several fundamental problems:
  3157.  *
  3158.  * - The characters in the preedit string are subject to remapping.
  3159.  *   That's broken, only the finally committed string should be remapped.
  3160.  *
  3161.  * - There is a race condition involved:  The retrieved value for the
  3162.  *   current cursor position will be wrong if any unprocessed characters
  3163.  *   are still queued in the input buffer.
  3164.  *
  3165.  * - Due to the lack of synchronization between the file buffer in memory
  3166.  *   and any typed characters, it's practically impossible to implement the
  3167.  *   "retrieve_surrounding" and "delete_surrounding" signals reliably.  IM
  3168.  *   modules for languages such as Thai are likely to rely on this feature
  3169.  *   for proper operation.
  3170.  *
  3171.  * Conclusions:  I think support for preediting needs to be moved to the
  3172.  * core parts of Vim.  Ideally, until it has been committed, the preediting
  3173.  * string should only be displayed and not affect the buffer content at all.
  3174.  * The question how to deal with the synchronization issue still remains.
  3175.  * Circumventing the input buffer is probably not desirable.  Anyway, I think
  3176.  * implementing "retrieve_surrounding" is the only hard problem.
  3177.  *
  3178.  * One way to solve all of this in a clean manner would be to queue all key
  3179.  * press/release events "as is" in the input buffer, and apply the IM filtering
  3180.  * at the receiving end of the queue.  This, however, would have a rather large
  3181.  * impact on the code base.  If there is an easy way to force processing of all
  3182.  * remaining input from within the "retrieve_surrounding" signal handler, this
  3183.  * might not be necessary.  Gotta ask on vim-dev for opinions.
  3184.  */
  3185. /*ARGSUSED1*/
  3186.     static void
  3187. im_preedit_changed_cb(GtkIMContext *context, gpointer data)
  3188. {
  3189.     char    *preedit_string = NULL;
  3190.     int        cursor_index    = 0;
  3191.     int        num_move_back   = 0;
  3192.     char_u  *str;
  3193.     char_u  *p;
  3194.     int        i;
  3195.  
  3196.     gtk_im_context_get_preedit_string(context,
  3197.                       &preedit_string, NULL,
  3198.                       &cursor_index);
  3199.  
  3200.     g_return_if_fail(preedit_string != NULL); /* just in case */
  3201.  
  3202.     if (preedit_start_col == MAXCOL && preedit_string[0] != '\0')
  3203.     {
  3204.     /* Urgh, this breaks if the input buffer isn't empty now */
  3205.     if (State & CMDLINE)
  3206.         preedit_start_col = cmdline_getvcol_cursor();
  3207.     else if (curwin != NULL)
  3208.         getvcol(curwin, &curwin->w_cursor, &preedit_start_col, NULL, NULL);
  3209.     }
  3210.  
  3211.     im_delete_preedit();
  3212.  
  3213.     str = (char_u *)preedit_string;
  3214.     /*
  3215.      * According to the documentation of gtk_im_context_get_preedit_string(),
  3216.      * the cursor_pos output argument returns the offset in bytes.  This is
  3217.      * unfortunately not true -- real life shows the offset is in characters,
  3218.      * and the GTK+ source code agrees with me.  Will file a bug later.
  3219.      */
  3220.     for (p = str, i = 0; *p != NUL; p += utf_byte2len(*p), ++i)
  3221.     {
  3222.     int is_composing;
  3223.  
  3224.     is_composing = ((*p & 0x80) != 0 && utf_iscomposing(utf_ptr2char(p)));
  3225.     /*
  3226.      * These offsets are used as counters when generating <BS> and <Del>
  3227.      * to delete the preedit string.  So don't count composing characters
  3228.      * unless 'delcombine' is enabled.
  3229.      */
  3230.     if (!is_composing || p_deco)
  3231.     {
  3232.         if (i < cursor_index)
  3233.         ++im_preedit_cursor;
  3234.         else
  3235.         ++im_preedit_trailing;
  3236.     }
  3237.     if (!is_composing && i >= cursor_index)
  3238.     {
  3239.         /* This is essentially the same as im_preedit_trailing, except
  3240.          * composing characters are not counted even if p_deco is set. */
  3241.         ++num_move_back;
  3242.     }
  3243.     }
  3244.  
  3245.     if (p > str)
  3246.     {
  3247.     im_add_to_input(str, (int)(p - str));
  3248.     im_correct_cursor(num_move_back);
  3249.     }
  3250.  
  3251.     g_free(preedit_string);
  3252.  
  3253.     if (gtk_main_level() > 0)
  3254.     gtk_main_quit();
  3255. }
  3256.  
  3257. /*
  3258.  * Translate the Pango attributes at iter to Vim highlighting attributes.
  3259.  * Ignore attributes not supported by Vim highlighting.  This shouldn't have
  3260.  * too much impact -- right now we handle even more attributes than necessary
  3261.  * for the IM modules I tested with.
  3262.  */
  3263.     static int
  3264. translate_pango_attributes(PangoAttrIterator *iter)
  3265. {
  3266.     PangoAttribute  *attr;
  3267.     int            char_attr = HL_NORMAL;
  3268.  
  3269.     attr = pango_attr_iterator_get(iter, PANGO_ATTR_UNDERLINE);
  3270.     if (attr != NULL && ((PangoAttrInt *)attr)->value
  3271.                          != (int)PANGO_UNDERLINE_NONE)
  3272.     char_attr |= HL_UNDERLINE;
  3273.  
  3274.     attr = pango_attr_iterator_get(iter, PANGO_ATTR_WEIGHT);
  3275.     if (attr != NULL && ((PangoAttrInt *)attr)->value >= (int)PANGO_WEIGHT_BOLD)
  3276.     char_attr |= HL_BOLD;
  3277.  
  3278.     attr = pango_attr_iterator_get(iter, PANGO_ATTR_STYLE);
  3279.     if (attr != NULL && ((PangoAttrInt *)attr)->value
  3280.                            != (int)PANGO_STYLE_NORMAL)
  3281.     char_attr |= HL_ITALIC;
  3282.  
  3283.     attr = pango_attr_iterator_get(iter, PANGO_ATTR_BACKGROUND);
  3284.     if (attr != NULL)
  3285.     {
  3286.     const PangoColor *color = &((PangoAttrColor *)attr)->color;
  3287.  
  3288.     /* Assume inverse if black background is requested */
  3289.     if ((color->red | color->green | color->blue) == 0)
  3290.         char_attr |= HL_INVERSE;
  3291.     }
  3292.  
  3293.     return char_attr;
  3294. }
  3295.  
  3296. /*
  3297.  * Retrieve the highlighting attributes at column col in the preedit string.
  3298.  * Return -1 if not in preediting mode or if col is out of range.
  3299.  */
  3300.     int
  3301. im_get_feedback_attr(int col)
  3302. {
  3303.     char        *preedit_string = NULL;
  3304.     PangoAttrList   *attr_list        = NULL;
  3305.     int            char_attr        = -1;
  3306.  
  3307.     if (xic == NULL)
  3308.     return char_attr;
  3309.  
  3310.     gtk_im_context_get_preedit_string(xic, &preedit_string, &attr_list, NULL);
  3311.  
  3312.     if (preedit_string != NULL && attr_list != NULL)
  3313.     {
  3314.     int index;
  3315.  
  3316.     /* Get the byte index as used by PangoAttrIterator */
  3317.     for (index = 0; col > 0 && preedit_string[index] != '\0'; --col)
  3318.         index += utfc_ptr2len_check((char_u *)preedit_string + index);
  3319.  
  3320.     if (preedit_string[index] != '\0')
  3321.     {
  3322.         PangoAttrIterator    *iter;
  3323.         int            start, end;
  3324.  
  3325.         char_attr = HL_NORMAL;
  3326.         iter = pango_attr_list_get_iterator(attr_list);
  3327.  
  3328.         /* Extract all relevant attributes from the list. */
  3329.         do
  3330.         {
  3331.         pango_attr_iterator_range(iter, &start, &end);
  3332.  
  3333.         if (index >= start && index < end)
  3334.             char_attr |= translate_pango_attributes(iter);
  3335.         }
  3336.         while (pango_attr_iterator_next(iter));
  3337.  
  3338.         pango_attr_iterator_destroy(iter);
  3339.     }
  3340.     }
  3341.  
  3342.     if (attr_list != NULL)
  3343.     pango_attr_list_unref(attr_list);
  3344.     g_free(preedit_string);
  3345.  
  3346.     return char_attr;
  3347. }
  3348.  
  3349.     void
  3350. xim_init(void)
  3351. {
  3352.     g_return_if_fail(gui.drawarea != NULL);
  3353.     g_return_if_fail(gui.drawarea->window != NULL);
  3354.  
  3355.     xic = gtk_im_multicontext_new();
  3356.  
  3357.     im_commit_handler_id = g_signal_connect(G_OBJECT(xic), "commit",
  3358.                         G_CALLBACK(&im_commit_cb), NULL);
  3359.     g_signal_connect(G_OBJECT(xic), "preedit_changed",
  3360.              G_CALLBACK(&im_preedit_changed_cb), NULL);
  3361.     g_signal_connect(G_OBJECT(xic), "preedit_start",
  3362.              G_CALLBACK(&im_preedit_start_cb), NULL);
  3363.     g_signal_connect(G_OBJECT(xic), "preedit_end",
  3364.              G_CALLBACK(&im_preedit_end_cb), NULL);
  3365.  
  3366.     gtk_im_context_set_client_window(xic, gui.drawarea->window);
  3367. }
  3368.  
  3369.     void
  3370. im_shutdown(void)
  3371. {
  3372.     if (xic != NULL)
  3373.     {
  3374.     gtk_im_context_focus_out(xic);
  3375.     g_object_unref(xic);
  3376.     xic = NULL;
  3377.     }
  3378.     im_is_active = FALSE;
  3379.     im_commit_handler_id = 0;
  3380.     preedit_start_col = MAXCOL;
  3381. }
  3382.  
  3383. /*
  3384.  * Convert the string argument to keyval and state for GdkEventKey.
  3385.  * If str is valid return TRUE, otherwise FALSE.
  3386.  *
  3387.  * See 'imactivatekey' for documentation of the format.
  3388.  */
  3389.     static int
  3390. im_string_to_keyval(const char *str, unsigned int *keyval, unsigned int *state)
  3391. {
  3392.     const char        *mods_end;
  3393.     unsigned        tmp_keyval;
  3394.     unsigned        tmp_state = 0;
  3395.  
  3396.     mods_end = strrchr(str, '-');
  3397.     mods_end = (mods_end != NULL) ? mods_end + 1 : str;
  3398.  
  3399.     /* Parse modifier keys */
  3400.     while (str < mods_end)
  3401.     switch (*str++)
  3402.     {
  3403.         case '-':                            break;
  3404.         case 'S': case 's': tmp_state |= (unsigned)GDK_SHIFT_MASK;    break;
  3405.         case 'L': case 'l': tmp_state |= (unsigned)GDK_LOCK_MASK;    break;
  3406.         case 'C': case 'c': tmp_state |= (unsigned)GDK_CONTROL_MASK;break;
  3407.         case '1':        tmp_state |= (unsigned)GDK_MOD1_MASK;    break;
  3408.         case '2':        tmp_state |= (unsigned)GDK_MOD2_MASK;    break;
  3409.         case '3':        tmp_state |= (unsigned)GDK_MOD3_MASK;    break;
  3410.         case '4':        tmp_state |= (unsigned)GDK_MOD4_MASK;    break;
  3411.         case '5':        tmp_state |= (unsigned)GDK_MOD5_MASK;    break;
  3412.         default:
  3413.         return FALSE;
  3414.     }
  3415.  
  3416.     tmp_keyval = gdk_keyval_from_name(str);
  3417.  
  3418.     if (tmp_keyval == 0 || tmp_keyval == GDK_VoidSymbol)
  3419.     return FALSE;
  3420.  
  3421.     if (keyval != NULL)
  3422.     *keyval = tmp_keyval;
  3423.     if (state != NULL)
  3424.     *state = tmp_state;
  3425.  
  3426.     return TRUE;
  3427. }
  3428.  
  3429. /*
  3430.  * Return TRUE if p_imak is valid, otherwise FALSE.  As a special case, an
  3431.  * empty string is also regarded as valid.
  3432.  *
  3433.  * Note: The numerical key value of p_imak is cached if it was valid; thus
  3434.  * boldly assuming im_xim_isvalid_imactivate() will always be called whenever
  3435.  * 'imak' changes.  This is currently the case but not obvious -- should
  3436.  * probably rename the function for clarity.
  3437.  */
  3438.     int
  3439. im_xim_isvalid_imactivate(void)
  3440. {
  3441.     if (p_imak[0] == NUL)
  3442.     {
  3443.     im_activatekey_keyval = GDK_VoidSymbol;
  3444.     im_activatekey_state  = 0;
  3445.     return TRUE;
  3446.     }
  3447.  
  3448.     return im_string_to_keyval((const char *)p_imak,
  3449.                    &im_activatekey_keyval,
  3450.                    &im_activatekey_state);
  3451. }
  3452.  
  3453.     static void
  3454. im_synthesize_keypress(unsigned int keyval, unsigned int state)
  3455. {
  3456.     GdkEventKey *event;
  3457.  
  3458. #  ifdef HAVE_GTK_MULTIHEAD
  3459.     event = (GdkEventKey *)gdk_event_new(GDK_KEY_PRESS);
  3460.     g_object_ref(gui.drawarea->window); /* unreffed by gdk_event_free() */
  3461. #  else
  3462.     event = (GdkEventKey *)g_malloc0((gulong)sizeof(GdkEvent));
  3463.     event->type = GDK_KEY_PRESS;
  3464. #  endif
  3465.     event->window = gui.drawarea->window;
  3466.     event->send_event = TRUE;
  3467.     event->time = GDK_CURRENT_TIME;
  3468.     event->state  = state;
  3469.     event->keyval = keyval;
  3470.     event->hardware_keycode = /* needed for XIM */
  3471.     XKeysymToKeycode(GDK_WINDOW_XDISPLAY(event->window), (KeySym)keyval);
  3472.     event->length = 0;
  3473.     event->string = NULL;
  3474.  
  3475.     gtk_im_context_filter_keypress(xic, event);
  3476.  
  3477.     /* For consistency, also send the corresponding release event. */
  3478.     event->type = GDK_KEY_RELEASE;
  3479.     event->send_event = FALSE;
  3480.     gtk_im_context_filter_keypress(xic, event);
  3481.  
  3482. #  ifdef HAVE_GTK_MULTIHEAD
  3483.     gdk_event_free((GdkEvent *)event);
  3484. #  else
  3485.     g_free(event);
  3486. #  endif
  3487. }
  3488.  
  3489.     void
  3490. xim_reset(void)
  3491. {
  3492.     if (xic != NULL)
  3493.     {
  3494.     /*
  3495.      * The third-party imhangul module (and maybe others too) ignores
  3496.      * gtk_im_context_reset() or at least doesn't reset the active state.
  3497.      * Thus sending imactivatekey would turn it off if it was on before,
  3498.      * which is clearly not what we want.  Fortunately we can work around
  3499.      * that for imhangul by sending GDK_Escape, but I don't know if it
  3500.      * works with all IM modules that support an activation key :/
  3501.      *
  3502.      * An alternative approach would be to destroy the IM context and
  3503.      * recreate it.  But that means loading/unloading the IM module on
  3504.      * every mode switch, which causes a quite noticable delay even on
  3505.      * my rather fast box...
  3506.      * *
  3507.      * Moreover, there are some XIM which cannot respond to
  3508.      * im_synthesize_keypress(). we hope that they reset by
  3509.      * xim_shutdown().
  3510.      */
  3511.     if (im_activatekey_keyval != GDK_VoidSymbol && im_is_active)
  3512.         im_synthesize_keypress(GDK_Escape, 0U);
  3513.  
  3514.     gtk_im_context_reset(xic);
  3515.     /*
  3516.      * HACK for Ami: This sequence of function calls makes Ami handle
  3517.      * the IM reset gratiously, without breaking loads of other stuff.
  3518.      * It seems to force English mode as well, which is exactly what we
  3519.      * want because it makes the Ami status display work reliably.
  3520.      */
  3521.     gtk_im_context_set_use_preedit(xic, FALSE);
  3522.     gtk_im_context_set_use_preedit(xic, TRUE);
  3523.     xim_set_focus(gui.in_focus);
  3524.  
  3525.     if (im_activatekey_keyval != GDK_VoidSymbol && im_is_active)
  3526.     {
  3527.         g_signal_handler_block(xic, im_commit_handler_id);
  3528.         im_synthesize_keypress(im_activatekey_keyval, im_activatekey_state);
  3529.         g_signal_handler_unblock(xic, im_commit_handler_id);
  3530.     }
  3531.     else
  3532.     {
  3533.         im_shutdown();
  3534.         xim_init();
  3535.         xim_set_focus(gui.in_focus);
  3536.     }
  3537.     }
  3538.  
  3539.     preedit_start_col = MAXCOL;
  3540. }
  3541.  
  3542.     int
  3543. xim_queue_key_press_event(GdkEventKey *event)
  3544. {
  3545.     /*
  3546.      * When typing fFtT, XIM may be activated. Thus it must pass
  3547.      * gtk_im_context_filter_keypress() in Normal mode.
  3548.      * And while doing :sh too.
  3549.      */
  3550.     if (xic != NULL && !p_imdisable
  3551.             && (State & (INSERT | CMDLINE | NORMAL | EXTERNCMD)) != 0)
  3552.     {
  3553.     /*
  3554.      * Filter 'imactivatekey' and map it to CTRL-^.  This way, Vim is
  3555.      * always aware of the current status of IM, and can even emulate
  3556.      * the activation key for modules that don't support one.
  3557.      */
  3558.     if (event->keyval == im_activatekey_keyval
  3559.          && (event->state & im_activatekey_state) == im_activatekey_state)
  3560.     {
  3561.         unsigned int state_mask;
  3562.  
  3563.         /* Require the state of the 3 most used modifiers to match exactly.
  3564.          * Otherwise e.g. <S-C-space> would be unusable for other purposes
  3565.          * if the IM activate key is <S-space>. */
  3566.         state_mask  = im_activatekey_state;
  3567.         state_mask |= ((int)GDK_SHIFT_MASK | (int)GDK_CONTROL_MASK
  3568.                             | (int)GDK_MOD1_MASK);
  3569.  
  3570.         if ((event->state & state_mask) != im_activatekey_state)
  3571.         return FALSE;
  3572.  
  3573.         /* Don't send it a second time on GDK_KEY_RELEASE. */
  3574.         if (event->type == GDK_KEY_PRESS)
  3575.         {
  3576.         char_u ctrl_hat[] = {Ctrl_HAT};
  3577.  
  3578.         add_to_input_buf(ctrl_hat, (int)sizeof(ctrl_hat));
  3579.  
  3580.         if (gtk_main_level() > 0)
  3581.             gtk_main_quit();
  3582.         }
  3583.         return TRUE;
  3584.     }
  3585.  
  3586.     /* Don't filter events through the IM context if IM isn't active
  3587.      * right now.  Unlike with GTK+ 1.2 we cannot rely on the IM module
  3588.      * not doing anything before the activation key was sent. */
  3589.     if (im_activatekey_keyval == GDK_VoidSymbol || im_is_active)
  3590.         return gtk_im_context_filter_keypress(xic, event);
  3591.     }
  3592.  
  3593.     return FALSE;
  3594. }
  3595.  
  3596.     int
  3597. im_get_status(void)
  3598. {
  3599.     return im_is_active;
  3600. }
  3601.  
  3602. # else /* !HAVE_GTK2 */
  3603.  
  3604. static int    xim_is_active = FALSE;  /* XIM should be active in the current
  3605.                        mode */
  3606. static int    xim_has_focus = FALSE;    /* XIM is really being used for Vim */
  3607. #ifdef FEAT_GUI_X11
  3608. static XIMStyle    input_style;
  3609. static int    status_area_enabled = TRUE;
  3610. #endif
  3611.  
  3612. #ifdef FEAT_GUI_GTK
  3613. # include <gdk/gdkx.h>
  3614. #else
  3615. # ifdef PROTO
  3616. /* Define a few things to be able to generate prototypes while not configured
  3617.  * for GTK. */
  3618. #  define GSList int
  3619. #  define gboolean int
  3620.    typedef int GdkEvent;
  3621.    typedef int GdkEventKey;
  3622. #  define GdkIC int
  3623. # endif
  3624. #endif
  3625.  
  3626. #if defined(FEAT_GUI_GTK) || defined(PROTO)
  3627. static int    preedit_buf_len = 0;
  3628. static int    xim_preediting INIT(= FALSE);    /* XIM in showmode() */
  3629. static int    xim_input_style;
  3630. #ifndef FEAT_GUI_GTK
  3631. # define gboolean int
  3632. #endif
  3633. static gboolean    use_status_area = 0;
  3634.  
  3635. static int im_xim_str2keycode __ARGS((unsigned int *code, unsigned int *state));
  3636. static void im_xim_send_event_imactivate __ARGS((void));
  3637.  
  3638. /*
  3639.  * Convert string to keycode and state for XKeyEvent.
  3640.  * When string is valid return OK, when invalid return FAIL.
  3641.  *
  3642.  * See 'imactivatekey' documentation for the format.
  3643.  */
  3644.     static int
  3645. im_xim_str2keycode(code, state)
  3646.     unsigned int *code;
  3647.     unsigned int *state;
  3648. {
  3649.     int        retval = OK;
  3650.     int        len;
  3651.     unsigned    keycode = 0, keystate = 0;
  3652.     Window    window;
  3653.     Display    *display;
  3654.     char_u    *flag_end;
  3655.     char_u    *str;
  3656.  
  3657.     if (*p_imak != NUL)
  3658.     {
  3659.     len = STRLEN(p_imak);
  3660.     for (flag_end = p_imak + len - 1;
  3661.                 flag_end > p_imak && *flag_end != '-'; --flag_end)
  3662.         ;
  3663.  
  3664.     /* Parse modifier keys */
  3665.     for (str = p_imak; str < flag_end; ++str)
  3666.     {
  3667.         switch (*str)
  3668.         {
  3669.         case 's': case 'S':
  3670.             keystate |= ShiftMask;
  3671.             break;
  3672.         case 'l': case 'L':
  3673.             keystate |= LockMask;
  3674.             break;
  3675.         case 'c': case 'C':
  3676.             keystate |= ControlMask;
  3677.             break;
  3678.         case '1':
  3679.             keystate |= Mod1Mask;
  3680.             break;
  3681.         case '2':
  3682.             keystate |= Mod2Mask;
  3683.             break;
  3684.         case '3':
  3685.             keystate |= Mod3Mask;
  3686.             break;
  3687.         case '4':
  3688.             keystate |= Mod4Mask;
  3689.             break;
  3690.         case '5':
  3691.             keystate |= Mod5Mask;
  3692.             break;
  3693.         case '-':
  3694.             break;
  3695.         default:
  3696.             retval = FAIL;
  3697.         }
  3698.     }
  3699.     if (*str == '-')
  3700.         ++str;
  3701.  
  3702.     /* Get keycode from string. */
  3703.     gui_get_x11_windis(&window, &display);
  3704.     if (display)
  3705.         keycode = XKeysymToKeycode(display, XStringToKeysym((char *)str));
  3706.     if (keycode == 0)
  3707.         retval = FAIL;
  3708.  
  3709.     if (code != NULL)
  3710.         *code = keycode;
  3711.     if (state != NULL)
  3712.         *state = keystate;
  3713.     }
  3714.     return retval;
  3715. }
  3716.  
  3717.     static void
  3718. im_xim_send_event_imactivate()
  3719. {
  3720.     /* Force turn on preedit state by symulate keypress event.
  3721.      * Keycode and state is specified by 'imactivatekey'.
  3722.      */
  3723.     XKeyEvent ev;
  3724.  
  3725.     gui_get_x11_windis(&ev.window, &ev.display);
  3726.     ev.root = RootWindow(ev.display, DefaultScreen(ev.display));
  3727.     ev.subwindow = None;
  3728.     ev.time = CurrentTime;
  3729.     ev.x = 1;
  3730.     ev.y = 1;
  3731.     ev.x_root = 1;
  3732.     ev.y_root = 1;
  3733.     ev.same_screen = 1;
  3734.     ev.type = KeyPress;
  3735.     if (im_xim_str2keycode(&ev.keycode, &ev.state) == OK)
  3736.     XSendEvent(ev.display, ev.window, 1, KeyPressMask, (XEvent*)&ev);
  3737. }
  3738.  
  3739. /*
  3740.  * Return TRUE if 'imactivatekey' has a valid value.
  3741.  */
  3742.     int
  3743. im_xim_isvalid_imactivate()
  3744. {
  3745.     return im_xim_str2keycode(NULL, NULL) == OK;
  3746. }
  3747. #endif /* FEAT_GUI_GTK */
  3748.  
  3749. /*
  3750.  * Switch using XIM on/off.  This is used by the code that changes "State".
  3751.  */
  3752.     void
  3753. im_set_active(active)
  3754.     int        active;
  3755. {
  3756.     if (xic == NULL)
  3757.     return;
  3758.  
  3759.     /* If 'imdisable' is set, XIM is never active. */
  3760.     if (p_imdisable)
  3761.     active = FALSE;
  3762. #ifndef FEAT_GUI_GTK
  3763.     else if (input_style & XIMPreeditPosition)
  3764.     /* There is a problem in switching XIM off when preediting is used,
  3765.      * and it is not clear how this can be solved.  For now, keep XIM on
  3766.      * all the time, like it was done in Vim 5.8. */
  3767.     active = TRUE;
  3768. #endif
  3769.  
  3770.     /* Remember the active state, it is needed when Vim gets keyboard focus. */
  3771.     xim_is_active = active;
  3772.  
  3773. #ifdef FEAT_GUI_GTK
  3774.     /* When 'imactivatekey' has valid key-string, try to control XIM preedit
  3775.      * state.  When 'imactivatekey' has no or invalid string, try old XIM
  3776.      * focus control.
  3777.      */
  3778.     if (*p_imak != NUL)
  3779.     {
  3780.     /* BASIC STRATEGY:
  3781.      * Destroy old Input Context (XIC), and create new one.  New XIC
  3782.      * would have a state of preedit that is off.  When argument:active
  3783.      * is false, that's all.  Else argument:active is true, send a key
  3784.      * event specified by 'imactivatekey' to activate XIM preedit state.
  3785.      */
  3786.  
  3787.     xim_is_active = TRUE; /* Disable old XIM focus control */
  3788.     /* If we can monitor preedit state with preedit callback functions,
  3789.      * try least creation of new XIC.
  3790.      */
  3791.     if (xim_input_style & (int)GDK_IM_PREEDIT_CALLBACKS)
  3792.     {
  3793.         if (xim_preediting && !active)
  3794.         {
  3795.         /* Force turn off preedit state.  With some IM
  3796.          * implementations, we cannot turn off preedit state by
  3797.          * symulate keypress event.  It is why using such a method
  3798.          * that destroy old IC (input context), and create new one.
  3799.          * When create new IC, its preedit state is usually off.
  3800.          */
  3801.         xim_reset();
  3802.         xim_set_focus(FALSE);
  3803.         gdk_ic_destroy(xic);
  3804.         xim_init();
  3805.         xim_preediting = FALSE;
  3806.         }
  3807.         else if (!xim_preediting && active)
  3808.         im_xim_send_event_imactivate();
  3809.     }
  3810.     else
  3811.     {
  3812.         /* First, force destroy old IC, and create new one.  It
  3813.          * symulates "turning off preedit state".
  3814.          */
  3815.         xim_set_focus(FALSE);
  3816.         gdk_ic_destroy(xic);
  3817.         xim_init();
  3818.         xim_preediting = FALSE;
  3819.  
  3820.         /* 2nd, when requested to activate IM, symulate this by sending
  3821.          * the event.
  3822.          */
  3823.         if (active)
  3824.         {
  3825.         im_xim_send_event_imactivate();
  3826.         xim_preediting = TRUE;
  3827.         }
  3828.     }
  3829.     }
  3830.     else
  3831.     {
  3832. # ifndef XIMPreeditUnKnown
  3833.     /* X11R5 doesn't have these, it looks safe enough to define here. */
  3834.     typedef unsigned long XIMPreeditState;
  3835. #  define XIMPreeditUnKnown    0L
  3836. #  define XIMPreeditEnable    1L
  3837. #  define XIMPreeditDisable    (1L<<1)
  3838. #  define XNPreeditState    "preeditState"
  3839. # endif
  3840.     XIMPreeditState preedit_state = XIMPreeditUnKnown;
  3841.     XVaNestedList preedit_attr;
  3842.     XIC pxic;
  3843.  
  3844.     preedit_attr = XVaCreateNestedList(0,
  3845.                 XNPreeditState, &preedit_state,
  3846.                 NULL);
  3847.     pxic = ((GdkICPrivate *)xic)->xic;
  3848.  
  3849.     if (!XGetICValues(pxic, XNPreeditAttributes, preedit_attr, NULL))
  3850.     {
  3851.         XFree(preedit_attr);
  3852.         preedit_attr = XVaCreateNestedList(0,
  3853.                 XNPreeditState,
  3854.                 active ? XIMPreeditEnable : XIMPreeditDisable,
  3855.                 NULL);
  3856.         XSetICValues(pxic, XNPreeditAttributes, preedit_attr, NULL);
  3857.         xim_preediting = active;
  3858.         xim_is_active = active;
  3859.     }
  3860.     XFree(preedit_attr);
  3861.     }
  3862.     if (xim_input_style & XIMPreeditCallbacks)
  3863.     {
  3864.     preedit_buf_len = 0;
  3865.     if (State & CMDLINE)
  3866.         preedit_start_col = cmdline_getvcol_cursor();
  3867.     else
  3868.         getvcol(curwin, &curwin->w_cursor, &preedit_start_col, NULL, NULL);
  3869.     }
  3870. #else
  3871. # if 0
  3872.     /* When had tested kinput2 + canna + Athena GUI version with
  3873.      * 'imactivatekey' is "s-space", im_xim_send_event_imactivate() did not
  3874.      * work correctly.  It just inserted one space.  I don't know why we
  3875.      * couldn't switch state of XIM preediting.  This is reason why these
  3876.      * codes are commented out.
  3877.      */
  3878.     /* First, force destroy old IC, and create new one.  It symulates
  3879.      * "turning off preedit state".
  3880.      */
  3881.     xim_set_focus(FALSE);
  3882.     XDestroyIC(xic);
  3883.     xic = NULL;
  3884.     xim_init();
  3885.  
  3886.     /* 2nd, when requested to activate IM, symulate this by sending the
  3887.      * event.
  3888.      */
  3889.     if (active)
  3890.         im_xim_send_event_imactivate();
  3891. # endif
  3892. #endif
  3893.     xim_set_preedit();
  3894. }
  3895.  
  3896. /*
  3897.  * Adjust using XIM for gaining or losing keyboard focus.  Also called when
  3898.  * "xim_is_active" changes.
  3899.  */
  3900.     void
  3901. xim_set_focus(focus)
  3902.     int        focus;
  3903. {
  3904.     if (xic == NULL)
  3905.     return;
  3906.  
  3907.     /*
  3908.      * XIM only gets focus when the Vim window has keyboard focus and XIM has
  3909.      * been set active for the current mode.
  3910.      */
  3911.     if (focus && xim_is_active)
  3912.     {
  3913.     if (!xim_has_focus)
  3914.     {
  3915.         xim_has_focus = TRUE;
  3916. #ifdef FEAT_GUI_GTK
  3917.         gdk_im_begin(xic, gui.drawarea->window);
  3918. #else
  3919.         XSetICFocus(xic);
  3920. #endif
  3921.     }
  3922.     }
  3923.     else
  3924.     {
  3925.     if (xim_has_focus)
  3926.     {
  3927.         xim_has_focus = FALSE;
  3928. #ifdef FEAT_GUI_GTK
  3929.         gdk_im_end();
  3930. #else
  3931.         XUnsetICFocus(xic);
  3932. #endif
  3933.     }
  3934.     }
  3935. }
  3936.  
  3937. /*ARGSUSED*/
  3938.     void
  3939. im_set_position(row, col)
  3940.     int        row;
  3941.     int        col;
  3942. {
  3943.     xim_set_preedit();
  3944. }
  3945.  
  3946. /*
  3947.  * Set the XIM to the current cursor position.
  3948.  */
  3949.     void
  3950. xim_set_preedit()
  3951. {
  3952.     if (xic == NULL)
  3953.     return;
  3954.  
  3955.     xim_set_focus(TRUE);
  3956.  
  3957. #ifdef FEAT_GUI_GTK
  3958.     if (gdk_im_ready())
  3959.     {
  3960.     int        attrmask;
  3961.     GdkICAttr    *attr;
  3962.  
  3963.     if (!xic_attr)
  3964.         return;
  3965.  
  3966.     attr = xic_attr;
  3967.     attrmask = 0;
  3968.  
  3969. # ifdef FEAT_XFONTSET
  3970.     if ((xim_input_style & (int)GDK_IM_PREEDIT_POSITION)
  3971.         && gui.fontset != NOFONTSET
  3972.         && gui.fontset->type == GDK_FONT_FONTSET)
  3973.     {
  3974.         if (!xim_has_focus)
  3975.         {
  3976.         if (attr->spot_location.y >= 0)
  3977.         {
  3978.             attr->spot_location.x = 0;
  3979.             attr->spot_location.y = -100;
  3980.             attrmask |= (int)GDK_IC_SPOT_LOCATION;
  3981.         }
  3982.         }
  3983.         else
  3984.         {
  3985.         gint    width, height;
  3986.  
  3987.         if (attr->spot_location.x != TEXT_X(gui.col)
  3988.             || attr->spot_location.y != TEXT_Y(gui.row))
  3989.         {
  3990.             attr->spot_location.x = TEXT_X(gui.col);
  3991.             attr->spot_location.y = TEXT_Y(gui.row);
  3992.             attrmask |= (int)GDK_IC_SPOT_LOCATION;
  3993.         }
  3994.  
  3995.         gdk_window_get_size(gui.drawarea->window, &width, &height);
  3996.         width -= 2 * gui.border_offset;
  3997.         height -= 2 * gui.border_offset;
  3998.         if (xim_input_style & (int)GDK_IM_STATUS_AREA)
  3999.             height -= gui.char_height;
  4000.         if (attr->preedit_area.width != width
  4001.             || attr->preedit_area.height != height)
  4002.         {
  4003.             attr->preedit_area.x = gui.border_offset;
  4004.             attr->preedit_area.y = gui.border_offset;
  4005.             attr->preedit_area.width = width;
  4006.             attr->preedit_area.height = height;
  4007.             attrmask |= (int)GDK_IC_PREEDIT_AREA;
  4008.         }
  4009.  
  4010.         if (attr->preedit_fontset != gui.current_font)
  4011.         {
  4012.             attr->preedit_fontset = gui.current_font;
  4013.             attrmask |= (int)GDK_IC_PREEDIT_FONTSET;
  4014.         }
  4015.         }
  4016.     }
  4017. # endif /* FEAT_XFONTSET */
  4018.  
  4019.     if (xim_fg_color == INVALCOLOR)
  4020.     {
  4021.         xim_fg_color = gui.def_norm_pixel;
  4022.         xim_bg_color = gui.def_back_pixel;
  4023.     }
  4024.     if (attr->preedit_foreground.pixel != xim_fg_color)
  4025.     {
  4026.         attr->preedit_foreground.pixel = xim_fg_color;
  4027.         attrmask |= (int)GDK_IC_PREEDIT_FOREGROUND;
  4028.     }
  4029.     if (attr->preedit_background.pixel != xim_bg_color)
  4030.     {
  4031.         attr->preedit_background.pixel = xim_bg_color;
  4032.         attrmask |= (int)GDK_IC_PREEDIT_BACKGROUND;
  4033.     }
  4034.  
  4035.     if (attrmask != 0)
  4036.         gdk_ic_set_attr(xic, attr, (GdkICAttributesType)attrmask);
  4037.     }
  4038. #else /* FEAT_GUI_GTK */
  4039.     {
  4040.     XVaNestedList attr_list;
  4041.     XRectangle spot_area;
  4042.     XPoint over_spot;
  4043.     int line_space;
  4044.  
  4045.     if (!xim_has_focus)
  4046.     {
  4047.         /* hide XIM cursor */
  4048.         over_spot.x = 0;
  4049.         over_spot.y = -100; /* arbitrary invisible position */
  4050.         attr_list = (XVaNestedList) XVaCreateNestedList(0,
  4051.                                 XNSpotLocation,
  4052.                                 &over_spot,
  4053.                                 NULL);
  4054.         XSetICValues(xic, XNPreeditAttributes, attr_list, NULL);
  4055.         XFree(attr_list);
  4056.         return;
  4057.     }
  4058.  
  4059.     if (input_style & XIMPreeditPosition)
  4060.     {
  4061.         if (xim_fg_color == INVALCOLOR)
  4062.         {
  4063.         xim_fg_color = gui.def_norm_pixel;
  4064.         xim_bg_color = gui.def_back_pixel;
  4065.         }
  4066.         over_spot.x = TEXT_X(gui.col);
  4067.         over_spot.y = TEXT_Y(gui.row);
  4068.         spot_area.x = 0;
  4069.         spot_area.y = 0;
  4070.         spot_area.height = gui.char_height * Rows;
  4071.         spot_area.width  = gui.char_width * Columns;
  4072.         line_space = gui.char_height;
  4073.         attr_list = (XVaNestedList) XVaCreateNestedList(0,
  4074.                         XNSpotLocation, &over_spot,
  4075.                         XNForeground, (Pixel) xim_fg_color,
  4076.                         XNBackground, (Pixel) xim_bg_color,
  4077.                         XNArea, &spot_area,
  4078.                         XNLineSpace, line_space,
  4079.                         NULL);
  4080.         if (XSetICValues(xic, XNPreeditAttributes, attr_list, NULL))
  4081.         EMSG(_("E284: Cannot set IC values"));
  4082.         XFree(attr_list);
  4083.     }
  4084.     }
  4085. #endif /* FEAT_GUI_GTK */
  4086. }
  4087.  
  4088. /*
  4089.  * Set up the status area.
  4090.  *
  4091.  * This should use a separate Widget, but that seems not possible, because
  4092.  * preedit_area and status_area should be set to the same window as for the
  4093.  * text input.  Unfortunately this means the status area pollutes the text
  4094.  * window...
  4095.  */
  4096.     void
  4097. xim_set_status_area()
  4098. {
  4099.     if (xic == NULL)
  4100.     return;
  4101.  
  4102. #ifdef FEAT_GUI_GTK
  4103. # if defined(FEAT_XFONTSET)
  4104.     if (use_status_area)
  4105.     {
  4106.     GdkICAttr    *attr;
  4107.     int        style;
  4108.     gint        width, height;
  4109.     GtkWidget    *widget;
  4110.     int        attrmask;
  4111.  
  4112.     if (!xic_attr)
  4113.         return;
  4114.  
  4115.     attr = xic_attr;
  4116.     attrmask = 0;
  4117.     style = (int)gdk_ic_get_style(xic);
  4118.     if ((style & (int)GDK_IM_STATUS_MASK) == (int)GDK_IM_STATUS_AREA)
  4119.     {
  4120.         if (gui.fontset != NOFONTSET
  4121.             && gui.fontset->type == GDK_FONT_FONTSET)
  4122.         {
  4123.         widget = gui.mainwin;
  4124.         gdk_window_get_size(widget->window, &width, &height);
  4125.  
  4126.         attrmask |= (int)GDK_IC_STATUS_AREA;
  4127.         attr->status_area.x = 0;
  4128.         attr->status_area.y = height - gui.char_height - 1;
  4129.         attr->status_area.width = width;
  4130.         attr->status_area.height = gui.char_height;
  4131.         }
  4132.     }
  4133.     if (attrmask != 0)
  4134.         gdk_ic_set_attr(xic, attr, (GdkICAttributesType)attrmask);
  4135.     }
  4136. # endif
  4137. #else
  4138.     {
  4139.     XVaNestedList preedit_list = 0, status_list = 0, list = 0;
  4140.     XRectangle pre_area, status_area;
  4141.  
  4142.     if (input_style & XIMStatusArea)
  4143.     {
  4144.         if (input_style & XIMPreeditArea)
  4145.         {
  4146.         XRectangle *needed_rect;
  4147.  
  4148.         /* to get status_area width */
  4149.         status_list = XVaCreateNestedList(0, XNAreaNeeded,
  4150.                           &needed_rect, NULL);
  4151.         XGetICValues(xic, XNStatusAttributes, status_list, NULL);
  4152.         XFree(status_list);
  4153.  
  4154.         status_area.width = needed_rect->width;
  4155.         }
  4156.         else
  4157.         status_area.width = gui.char_width * Columns;
  4158.  
  4159.         status_area.x = 0;
  4160.         status_area.y = gui.char_height * Rows + gui.border_offset;
  4161.         if (gui.which_scrollbars[SBAR_BOTTOM])
  4162.         status_area.y += gui.scrollbar_height;
  4163. #ifdef FEAT_MENU
  4164.         if (gui.menu_is_active)
  4165.         status_area.y += gui.menu_height;
  4166. #endif
  4167.         status_area.height = gui.char_height;
  4168.         status_list = XVaCreateNestedList(0, XNArea, &status_area, NULL);
  4169.     }
  4170.     else
  4171.     {
  4172.         status_area.x = 0;
  4173.         status_area.y = gui.char_height * Rows + gui.border_offset;
  4174.         if (gui.which_scrollbars[SBAR_BOTTOM])
  4175.         status_area.y += gui.scrollbar_height;
  4176. #ifdef FEAT_MENU
  4177.         if (gui.menu_is_active)
  4178.         status_area.y += gui.menu_height;
  4179. #endif
  4180.         status_area.width = 0;
  4181.         status_area.height = gui.char_height;
  4182.     }
  4183.  
  4184.     if (input_style & XIMPreeditArea)   /* off-the-spot */
  4185.     {
  4186.         pre_area.x = status_area.x + status_area.width;
  4187.         pre_area.y = gui.char_height * Rows + gui.border_offset;
  4188.         pre_area.width = gui.char_width * Columns - pre_area.x;
  4189.         if (gui.which_scrollbars[SBAR_BOTTOM])
  4190.         pre_area.y += gui.scrollbar_height;
  4191. #ifdef FEAT_MENU
  4192.         if (gui.menu_is_active)
  4193.         pre_area.y += gui.menu_height;
  4194. #endif
  4195.         pre_area.height = gui.char_height;
  4196.         preedit_list = XVaCreateNestedList(0, XNArea, &pre_area, NULL);
  4197.     }
  4198.     else if (input_style & XIMPreeditPosition)   /* over-the-spot */
  4199.     {
  4200.         pre_area.x = 0;
  4201.         pre_area.y = 0;
  4202.         pre_area.height = gui.char_height * Rows;
  4203.         pre_area.width = gui.char_width * Columns;
  4204.         preedit_list = XVaCreateNestedList(0, XNArea, &pre_area, NULL);
  4205.     }
  4206.  
  4207.     if (preedit_list && status_list)
  4208.         list = XVaCreateNestedList(0, XNPreeditAttributes, preedit_list,
  4209.                        XNStatusAttributes, status_list, NULL);
  4210.     else if (preedit_list)
  4211.         list = XVaCreateNestedList(0, XNPreeditAttributes, preedit_list,
  4212.                        NULL);
  4213.     else if (status_list)
  4214.         list = XVaCreateNestedList(0, XNStatusAttributes, status_list,
  4215.                        NULL);
  4216.     else
  4217.         list = NULL;
  4218.  
  4219.     if (list)
  4220.     {
  4221.         XSetICValues(xic, XNVaNestedList, list, NULL);
  4222.         XFree(list);
  4223.     }
  4224.     if (status_list)
  4225.         XFree(status_list);
  4226.     if (preedit_list)
  4227.         XFree(preedit_list);
  4228.     }
  4229. #endif
  4230. }
  4231.  
  4232. #if defined(FEAT_GUI_X11) || defined(FEAT_GUI_GTK)
  4233. static char e_xim[] = N_("E285: Failed to create input context");
  4234. #endif
  4235.  
  4236. #if defined(FEAT_GUI_X11) || defined(PROTO)
  4237. # if defined(XtSpecificationRelease) && XtSpecificationRelease >= 6 && !defined(sun)
  4238. #  define USE_X11R6_XIM
  4239. # endif
  4240.  
  4241. static int xim_real_init __ARGS((Window x11_window, Display *x11_display));
  4242.  
  4243.  
  4244. #ifdef USE_X11R6_XIM
  4245. static void xim_instantiate_cb __ARGS((Display *display, XPointer client_data, XPointer    call_data));
  4246. static void xim_destroy_cb __ARGS((XIM im, XPointer client_data, XPointer call_data));
  4247.  
  4248. /*ARGSUSED*/
  4249.     static void
  4250. xim_instantiate_cb(display, client_data, call_data)
  4251.     Display    *display;
  4252.     XPointer    client_data;
  4253.     XPointer    call_data;
  4254. {
  4255.     Window    x11_window;
  4256.     Display    *x11_display;
  4257.  
  4258.     gui_get_x11_windis(&x11_window, &x11_display);
  4259.     if (display != x11_display)
  4260.     return;
  4261.  
  4262.     xim_real_init(x11_window, x11_display);
  4263.     gui_set_shellsize(FALSE, FALSE);
  4264.     if (xic != NULL)
  4265.     XUnregisterIMInstantiateCallback(x11_display, NULL, NULL, NULL,
  4266.                      xim_instantiate_cb, NULL);
  4267. }
  4268.  
  4269. /*ARGSUSED*/
  4270.     static void
  4271. xim_destroy_cb(im, client_data, call_data)
  4272.     XIM        im;
  4273.     XPointer    client_data;
  4274.     XPointer    call_data;
  4275. {
  4276.     Window    x11_window;
  4277.     Display    *x11_display;
  4278.  
  4279.     gui_get_x11_windis(&x11_window, &x11_display);
  4280.  
  4281.     xic = NULL;
  4282.     status_area_enabled = FALSE;
  4283.  
  4284.     gui_set_shellsize(FALSE, FALSE);
  4285.  
  4286.     XRegisterIMInstantiateCallback(x11_display, NULL, NULL, NULL,
  4287.                    xim_instantiate_cb, NULL);
  4288. }
  4289. #endif
  4290.  
  4291.     void
  4292. xim_init()
  4293. {
  4294.     Window    x11_window;
  4295.     Display    *x11_display;
  4296.  
  4297.     gui_get_x11_windis(&x11_window, &x11_display);
  4298.  
  4299.     xic = NULL;
  4300.  
  4301.     if (xim_real_init(x11_window, x11_display))
  4302.     return;
  4303.  
  4304.     gui_set_shellsize(FALSE, FALSE);
  4305.  
  4306. #ifdef USE_X11R6_XIM
  4307.     XRegisterIMInstantiateCallback(x11_display, NULL, NULL, NULL,
  4308.                    xim_instantiate_cb, NULL);
  4309. #endif
  4310. }
  4311.  
  4312.     static int
  4313. xim_real_init(x11_window, x11_display)
  4314.     Window    x11_window;
  4315.     Display    *x11_display;
  4316. {
  4317.     int        i;
  4318.     char    *p,
  4319.         *s,
  4320.         *ns,
  4321.         *end,
  4322.         tmp[1024];
  4323. #define IMLEN_MAX 40
  4324.     char    buf[IMLEN_MAX + 7];
  4325.     XIM        xim = NULL;
  4326.     XIMStyles    *xim_styles;
  4327.     XIMStyle    this_input_style = 0;
  4328.     Boolean    found;
  4329.     XPoint    over_spot;
  4330.     XVaNestedList preedit_list, status_list;
  4331.  
  4332.     input_style = 0;
  4333.     status_area_enabled = FALSE;
  4334.  
  4335.     if (xic != NULL)
  4336.     return FALSE;
  4337.  
  4338.     if (gui.rsrc_input_method != NULL && *gui.rsrc_input_method != NUL)
  4339.     {
  4340.     strcpy(tmp, gui.rsrc_input_method);
  4341.     for (ns = s = tmp; ns != NULL && *s != NUL;)
  4342.     {
  4343.         s = (char *)skipwhite((char_u *)s);
  4344.         if (*s == NUL)
  4345.         break;
  4346.         if ((ns = end = strchr(s, ',')) == NULL)
  4347.         end = s + strlen(s);
  4348.         while (isspace(((char_u *)end)[-1]))
  4349.         end--;
  4350.         *end = NUL;
  4351.  
  4352.         if (strlen(s) <= IMLEN_MAX)
  4353.         {
  4354.         strcpy(buf, "@im=");
  4355.         strcat(buf, s);
  4356.         if ((p = XSetLocaleModifiers(buf)) != NULL && *p != NUL
  4357.             && (xim = XOpenIM(x11_display, NULL, NULL, NULL))
  4358.                                       != NULL)
  4359.             break;
  4360.         }
  4361.  
  4362.         s = ns + 1;
  4363.     }
  4364.     }
  4365.  
  4366.     if (xim == NULL && (p = XSetLocaleModifiers("")) != NULL && *p != NUL)
  4367.     xim = XOpenIM(x11_display, NULL, NULL, NULL);
  4368.  
  4369.     /* This is supposed to be useful to obtain characters through
  4370.      * XmbLookupString() without really using a XIM. */
  4371.     if (xim == NULL && (p = XSetLocaleModifiers("@im=none")) != NULL
  4372.                                  && *p != NUL)
  4373.     xim = XOpenIM(x11_display, NULL, NULL, NULL);
  4374.  
  4375.     if (xim == NULL)
  4376.     {
  4377.     /* Only give this message when verbose is set, because too many people
  4378.      * got this message when they didn't want to use a XIM. */
  4379.     if (p_verbose > 0)
  4380.         EMSG(_("E286: Failed to open input method"));
  4381.     return FALSE;
  4382.     }
  4383.  
  4384. #ifdef USE_X11R6_XIM
  4385.     {
  4386.     XIMCallback destroy_cb;
  4387.  
  4388.     destroy_cb.callback = xim_destroy_cb;
  4389.     destroy_cb.client_data = NULL;
  4390.     if (XSetIMValues(xim, XNDestroyCallback, &destroy_cb, NULL))
  4391.         EMSG(_("E287: Warning: Could not set destroy callback to IM"));
  4392.     }
  4393. #endif
  4394.  
  4395.     if (XGetIMValues(xim, XNQueryInputStyle, &xim_styles, NULL) || !xim_styles)
  4396.     {
  4397.     EMSG(_("E288: input method doesn't support any style"));
  4398.     XCloseIM(xim);
  4399.     return FALSE;
  4400.     }
  4401.  
  4402.     found = False;
  4403.     strcpy(tmp, gui.rsrc_preedit_type_name);
  4404.     for (s = tmp; s && !found; )
  4405.     {
  4406.     while (*s && isspace((unsigned char)*s))
  4407.         s++;
  4408.     if (!*s)
  4409.         break;
  4410.     if ((ns = end = strchr(s, ',')) != 0)
  4411.         ns++;
  4412.     else
  4413.         end = s + strlen(s);
  4414.     while (isspace((unsigned char)*end))
  4415.         end--;
  4416.     *end = '\0';
  4417.  
  4418.     if (!strcmp(s, "OverTheSpot"))
  4419.         this_input_style = (XIMPreeditPosition | XIMStatusArea);
  4420.     else if (!strcmp(s, "OffTheSpot"))
  4421.         this_input_style = (XIMPreeditArea | XIMStatusArea);
  4422.     else if (!strcmp(s, "Root"))
  4423.         this_input_style = (XIMPreeditNothing | XIMStatusNothing);
  4424.  
  4425.     for (i = 0; (unsigned short)i < xim_styles->count_styles; i++)
  4426.     {
  4427.         if (this_input_style == xim_styles->supported_styles[i])
  4428.         {
  4429.         found = True;
  4430.         break;
  4431.         }
  4432.     }
  4433.     if (!found)
  4434.         for (i = 0; (unsigned short)i < xim_styles->count_styles; i++)
  4435.         {
  4436.         if ((xim_styles->supported_styles[i] & this_input_style)
  4437.             == (this_input_style & ~XIMStatusArea))
  4438.         {
  4439.             this_input_style &= ~XIMStatusArea;
  4440.             found = True;
  4441.             break;
  4442.         }
  4443.         }
  4444.  
  4445.     s = ns;
  4446.     }
  4447.     XFree(xim_styles);
  4448.  
  4449.     if (!found)
  4450.     {
  4451.     /* Only give this message when verbose is set, because too many people
  4452.      * got this message when they didn't want to use a XIM. */
  4453.     if (p_verbose > 0)
  4454.         EMSG(_("E289: input method doesn't support my preedit type"));
  4455.     XCloseIM(xim);
  4456.     return FALSE;
  4457.     }
  4458.  
  4459.     over_spot.x = TEXT_X(gui.col);
  4460.     over_spot.y = TEXT_Y(gui.row);
  4461.     input_style = this_input_style;
  4462.  
  4463.     /* A crash was reported when trying to pass gui.norm_font as XNFontSet,
  4464.      * thus that has been removed.  Hopefully the default works... */
  4465. #ifdef FEAT_XFONTSET
  4466.     if (gui.fontset != NOFONTSET)
  4467.     {
  4468.     preedit_list = XVaCreateNestedList(0,
  4469.                 XNSpotLocation, &over_spot,
  4470.                 XNForeground, (Pixel)gui.def_norm_pixel,
  4471.                 XNBackground, (Pixel)gui.def_back_pixel,
  4472.                 XNFontSet, (XFontSet)gui.fontset,
  4473.                 NULL);
  4474.     status_list = XVaCreateNestedList(0,
  4475.                 XNForeground, (Pixel)gui.def_norm_pixel,
  4476.                 XNBackground, (Pixel)gui.def_back_pixel,
  4477.                 XNFontSet, (XFontSet)gui.fontset,
  4478.                 NULL);
  4479.     }
  4480.     else
  4481. #endif
  4482.     {
  4483.     preedit_list = XVaCreateNestedList(0,
  4484.                 XNSpotLocation, &over_spot,
  4485.                 XNForeground, (Pixel)gui.def_norm_pixel,
  4486.                 XNBackground, (Pixel)gui.def_back_pixel,
  4487.                 NULL);
  4488.     status_list = XVaCreateNestedList(0,
  4489.                 XNForeground, (Pixel)gui.def_norm_pixel,
  4490.                 XNBackground, (Pixel)gui.def_back_pixel,
  4491.                 NULL);
  4492.     }
  4493.  
  4494.     xic = XCreateIC(xim,
  4495.             XNInputStyle, input_style,
  4496.             XNClientWindow, x11_window,
  4497.             XNFocusWindow, gui.wid,
  4498.             XNPreeditAttributes, preedit_list,
  4499.             XNStatusAttributes, status_list,
  4500.             NULL);
  4501.     XFree(status_list);
  4502.     XFree(preedit_list);
  4503.     if (xic != NULL)
  4504.     {
  4505.     if (input_style & XIMStatusArea)
  4506.     {
  4507.         xim_set_status_area();
  4508.         status_area_enabled = TRUE;
  4509.     }
  4510.     else
  4511.         gui_set_shellsize(FALSE, FALSE);
  4512.     }
  4513.     else
  4514.     {
  4515.     EMSG(_(e_xim));
  4516.     XCloseIM(xim);
  4517.     return FALSE;
  4518.     }
  4519.  
  4520.     return TRUE;
  4521. }
  4522.  
  4523. #endif /* FEAT_GUI_X11 */
  4524.  
  4525. #if defined(FEAT_GUI_GTK) || defined(PROTO)
  4526.  
  4527. # ifdef FEAT_XFONTSET
  4528. static char e_overthespot[] = N_("E290: over-the-spot style requires fontset");
  4529. # endif
  4530.  
  4531. # ifdef PROTO
  4532. typedef int GdkIC;
  4533. # endif
  4534.  
  4535.     void
  4536. xim_decide_input_style()
  4537. {
  4538.     /* GDK_IM_STATUS_CALLBACKS was disabled, enabled it to allow Japanese
  4539.      * OverTheSpot. */
  4540.     int supported_style = (int)GDK_IM_PREEDIT_NONE |
  4541.                  (int)GDK_IM_PREEDIT_NOTHING |
  4542.                  (int)GDK_IM_PREEDIT_POSITION |
  4543.                  (int)GDK_IM_PREEDIT_CALLBACKS |
  4544.                  (int)GDK_IM_STATUS_CALLBACKS |
  4545.                  (int)GDK_IM_STATUS_AREA |
  4546.                  (int)GDK_IM_STATUS_NONE |
  4547.                  (int)GDK_IM_STATUS_NOTHING;
  4548.  
  4549.     if (!gdk_im_ready())
  4550.     xim_input_style = 0;
  4551.     else
  4552.     {
  4553.     if (gtk_major_version > 1
  4554.         || (gtk_major_version == 1
  4555.             && (gtk_minor_version > 2
  4556.             || (gtk_minor_version == 2 && gtk_micro_version >= 3))))
  4557.         use_status_area = TRUE;
  4558.     else
  4559.     {
  4560.         EMSG(_("E291: Your GTK+ is older than 1.2.3. Status area disabled"));
  4561.         use_status_area = FALSE;
  4562.     }
  4563. #ifdef FEAT_XFONTSET
  4564.     if (gui.fontset == NOFONTSET || gui.fontset->type != GDK_FONT_FONTSET)
  4565. #endif
  4566.         supported_style &= ~((int)GDK_IM_PREEDIT_POSITION
  4567.                            | (int)GDK_IM_STATUS_AREA);
  4568.     if (!use_status_area)
  4569.         supported_style &= ~(int)GDK_IM_STATUS_AREA;
  4570.     xim_input_style = (int)gdk_im_decide_style((GdkIMStyle)supported_style);
  4571.     }
  4572. }
  4573.  
  4574. /*ARGSUSED*/
  4575.     static void
  4576. preedit_start_cbproc(XIC xic, XPointer client_data, XPointer call_data)
  4577. {
  4578.     draw_feedback = NULL;
  4579.     xim_preediting = TRUE;
  4580.     gui_update_cursor(TRUE, FALSE);
  4581.     if (showmode() > 0)
  4582.     {
  4583.     setcursor();
  4584.     out_flush();
  4585.     }
  4586. }
  4587.  
  4588.     static void
  4589. xim_back_delete(int n)
  4590. {
  4591.     char_u str[3];
  4592.  
  4593.     str[0] = CSI;
  4594.     str[1] = 'k';
  4595.     str[2] = 'b';
  4596.     while (n-- > 0)
  4597.     add_to_input_buf(str, 3);
  4598. }
  4599.  
  4600. static GSList *key_press_event_queue = NULL;
  4601. static gboolean processing_queued_event = FALSE;
  4602.  
  4603. /*ARGSUSED*/
  4604.     static void
  4605. preedit_draw_cbproc(XIC xic, XPointer client_data, XPointer call_data)
  4606. {
  4607.     XIMPreeditDrawCallbackStruct *draw_data;
  4608.     XIMText    *text;
  4609.     char    *src;
  4610.     GSList    *event_queue;
  4611.  
  4612.     draw_data = (XIMPreeditDrawCallbackStruct *) call_data;
  4613.     text = (XIMText *) draw_data->text;
  4614.  
  4615.     if ((text == NULL && draw_data->chg_length == preedit_buf_len)
  4616.         || preedit_buf_len == 0)
  4617.     {
  4618.     if (State & CMDLINE)
  4619.         preedit_start_col = cmdline_getvcol_cursor();
  4620.     else
  4621.         getvcol(curwin, &curwin->w_cursor, &preedit_start_col, NULL, NULL);
  4622.     vim_free(draw_feedback);
  4623.     draw_feedback = NULL;
  4624.     }
  4625.     if (draw_data->chg_length > 0)
  4626.     {
  4627.     int bs_cnt;
  4628.  
  4629.     if (draw_data->chg_length > preedit_buf_len)
  4630.         bs_cnt = preedit_buf_len;
  4631.     else
  4632.         bs_cnt = draw_data->chg_length;
  4633.     xim_back_delete(bs_cnt);
  4634.     preedit_buf_len -= bs_cnt;
  4635.     }
  4636.     if (text != NULL)
  4637.     {
  4638.     int        len;
  4639. #ifdef FEAT_MBYTE
  4640.     char_u        *buf = NULL;
  4641.     unsigned int    nfeedback = 0;
  4642. #endif
  4643.     char_u        *ptr;
  4644.  
  4645.     src = text->string.multi_byte;
  4646.     if (src != NULL && !text->encoding_is_wchar)
  4647.     {
  4648.         len = strlen(src);
  4649.         ptr = (char_u *)src;
  4650.         /* Avoid the enter for decision */
  4651.         if (*ptr == '\n')
  4652.         return;
  4653.  
  4654. #ifdef FEAT_MBYTE
  4655.         if (input_conv.vc_type != CONV_NONE
  4656.             && (buf = string_convert(&input_conv,
  4657.                          (char_u *)src, &len)) != NULL)
  4658.         {
  4659.         /* Converted from 'termencoding' to 'encoding'. */
  4660.         add_to_input_buf_csi(buf, len);
  4661.         ptr = buf;
  4662.         }
  4663.         else
  4664. #endif
  4665.         add_to_input_buf_csi((char_u *)src, len);
  4666.         /* Add count of character to preedit_buf_len  */
  4667.         while (*ptr != NUL)
  4668.         {
  4669. #ifdef FEAT_MBYTE
  4670.         if (draw_data->text->feedback != NULL)
  4671.         {
  4672.             if (draw_feedback == NULL)
  4673.             draw_feedback = (char *)alloc(draw_data->chg_first
  4674.                                   + text->length);
  4675.             else
  4676.             draw_feedback = realloc(draw_feedback,
  4677.                      draw_data->chg_first + text->length);
  4678.             if (draw_feedback != NULL)
  4679.             {
  4680.             draw_feedback[nfeedback + draw_data->chg_first]
  4681.                        = draw_data->text->feedback[nfeedback];
  4682.             nfeedback++;
  4683.             }
  4684.         }
  4685.         if (has_mbyte)
  4686.             ptr += mb_ptr2len_check(ptr);
  4687.         else
  4688. #endif
  4689.             ptr++;
  4690.         preedit_buf_len++;
  4691.         }
  4692. #ifdef FEAT_MBYTE
  4693.         vim_free(buf);
  4694. #endif
  4695.     }
  4696.     }
  4697.     if (text != NULL || draw_data->chg_length > 0)
  4698.     {
  4699.     event_queue = key_press_event_queue;
  4700.     processing_queued_event = TRUE;
  4701.     while (event_queue != NULL && processing_queued_event)
  4702.     {
  4703.         GdkEvent *ev = event_queue->data;
  4704.  
  4705.         gboolean *ret;
  4706.         gtk_signal_emit_by_name((GtkObject*)gui.mainwin, "key_press_event",
  4707.                                     ev, &ret);
  4708.         gdk_event_free(ev);
  4709.         event_queue = event_queue->next;
  4710.     }
  4711.     processing_queued_event = FALSE;
  4712.     if (key_press_event_queue)
  4713.     {
  4714.         g_slist_free(key_press_event_queue);
  4715.         key_press_event_queue = NULL;
  4716.     }
  4717.     }
  4718.     if (gtk_main_level() > 0)
  4719.     gtk_main_quit();
  4720. }
  4721.  
  4722. /*
  4723.  * Retrieve the highlighting attributes at column col in the preedit string.
  4724.  * Return -1 if not in preediting mode or if col is out of range.
  4725.  */
  4726.     int
  4727. im_get_feedback_attr(int col)
  4728. {
  4729.     if (draw_feedback != NULL && col < preedit_buf_len)
  4730.     {
  4731.     if (draw_feedback[col] & XIMReverse)
  4732.         return HL_INVERSE;
  4733.     else if (draw_feedback[col] & XIMUnderline)
  4734.         return HL_UNDERLINE;
  4735.     else
  4736.         return hl_attr(HLF_V);
  4737.     }
  4738.  
  4739.     return -1;
  4740. }
  4741.  
  4742. /*ARGSUSED*/
  4743.     static void
  4744. preedit_caret_cbproc(XIC xic, XPointer client_data, XPointer call_data)
  4745. {
  4746. }
  4747.  
  4748. /*ARGSUSED*/
  4749.     static void
  4750. preedit_done_cbproc(XIC xic, XPointer client_data, XPointer call_data)
  4751. {
  4752.     vim_free(draw_feedback);
  4753.     draw_feedback = NULL;
  4754.     xim_preediting = FALSE;
  4755.     gui_update_cursor(TRUE, FALSE);
  4756.     if (showmode() > 0)
  4757.     {
  4758.     setcursor();
  4759.     out_flush();
  4760.     }
  4761. }
  4762.  
  4763.     void
  4764. xim_reset(void)
  4765. {
  4766.     char *text;
  4767.  
  4768.     if (xic != NULL)
  4769.     {
  4770.     text = XmbResetIC(((GdkICPrivate *)xic)->xic);
  4771.     if (text != NULL && !(xim_input_style & (int)GDK_IM_PREEDIT_CALLBACKS))
  4772.         add_to_input_buf_csi((char_u *)text, strlen(text));
  4773.     else
  4774.         preedit_buf_len = 0;
  4775.     if (text != NULL)
  4776.         XFree(text);
  4777.     }
  4778. }
  4779.  
  4780.     int
  4781. xim_queue_key_press_event(GdkEventKey *event)
  4782. {
  4783.     if (preedit_buf_len <= 0)
  4784.     return FALSE;
  4785.     if (processing_queued_event)
  4786.     processing_queued_event = FALSE;
  4787.  
  4788.     key_press_event_queue = g_slist_append(key_press_event_queue,
  4789.                        gdk_event_copy((GdkEvent *)event));
  4790.     return TRUE;
  4791. }
  4792.  
  4793. /*ARGSUSED*/
  4794.     static void
  4795. preedit_callback_setup(GdkIC *ic)
  4796. {
  4797.     XIC xxic;
  4798.     XVaNestedList preedit_attr;
  4799.     XIMCallback preedit_start_cb;
  4800.     XIMCallback preedit_draw_cb;
  4801.     XIMCallback preedit_caret_cb;
  4802.     XIMCallback preedit_done_cb;
  4803.  
  4804.     xxic = ((GdkICPrivate*)xic)->xic;
  4805.     preedit_start_cb.callback = (XIMProc)preedit_start_cbproc;
  4806.     preedit_draw_cb.callback = (XIMProc)preedit_draw_cbproc;
  4807.     preedit_caret_cb.callback = (XIMProc)preedit_caret_cbproc;
  4808.     preedit_done_cb.callback = (XIMProc)preedit_done_cbproc;
  4809.     preedit_attr
  4810.     = XVaCreateNestedList (0,
  4811.                    XNPreeditStartCallback, &preedit_start_cb,
  4812.                    XNPreeditDrawCallback, &preedit_draw_cb,
  4813.                    XNPreeditCaretCallback, &preedit_caret_cb,
  4814.                    XNPreeditDoneCallback, &preedit_done_cb,
  4815.                    0);
  4816.     XSetICValues (xxic, XNPreeditAttributes, preedit_attr, 0);
  4817.     XFree(preedit_attr);
  4818. }
  4819.  
  4820. /*ARGSUSED*/
  4821.     static void
  4822. reset_state_setup(GdkIC *ic)
  4823. {
  4824. #ifdef USE_X11R6_XIM
  4825.     /* don't change the input context when we call reset */
  4826.     XSetICValues(((GdkICPrivate*)ic)->xic, XNResetState, XIMPreserveState, 0);
  4827. #endif
  4828. }
  4829.  
  4830.     void
  4831. xim_init(void)
  4832. {
  4833.     xic = NULL;
  4834.     xic_attr = NULL;
  4835.  
  4836.     if (!gdk_im_ready())
  4837.     {
  4838.     if (p_verbose > 0)
  4839.         EMSG(_("E292: Input Method Server is not running"));
  4840.     return;
  4841.     }
  4842.     if ((xic_attr = gdk_ic_attr_new()) != NULL)
  4843.     {
  4844. #ifdef FEAT_XFONTSET
  4845.     gint width, height;
  4846. #endif
  4847.     int        mask;
  4848.     GdkColormap    *colormap;
  4849.     GdkICAttr    *attr = xic_attr;
  4850.     int        attrmask = (int)GDK_IC_ALL_REQ;
  4851.     GtkWidget    *widget = gui.drawarea;
  4852.  
  4853.     attr->style = (GdkIMStyle)xim_input_style;
  4854.     attr->client_window = gui.mainwin->window;
  4855.  
  4856.     if ((colormap = gtk_widget_get_colormap(widget)) !=
  4857.         gtk_widget_get_default_colormap())
  4858.     {
  4859.         attrmask |= (int)GDK_IC_PREEDIT_COLORMAP;
  4860.         attr->preedit_colormap = colormap;
  4861.     }
  4862.     attrmask |= (int)GDK_IC_PREEDIT_FOREGROUND;
  4863.     attrmask |= (int)GDK_IC_PREEDIT_BACKGROUND;
  4864.     attr->preedit_foreground = widget->style->fg[GTK_STATE_NORMAL];
  4865.     attr->preedit_background = widget->style->base[GTK_STATE_NORMAL];
  4866.  
  4867. #ifdef FEAT_XFONTSET
  4868.     if ((xim_input_style & (int)GDK_IM_PREEDIT_MASK)
  4869.                           == (int)GDK_IM_PREEDIT_POSITION)
  4870.     {
  4871.         if (gui.fontset == NOFONTSET
  4872.             || gui.fontset->type != GDK_FONT_FONTSET)
  4873.         {
  4874.         EMSG(_(e_overthespot));
  4875.         }
  4876.         else
  4877.         {
  4878.         gdk_window_get_size(widget->window, &width, &height);
  4879.  
  4880.         attrmask |= (int)GDK_IC_PREEDIT_POSITION_REQ;
  4881.         attr->spot_location.x = TEXT_X(0);
  4882.         attr->spot_location.y = TEXT_Y(0);
  4883.         attr->preedit_area.x = gui.border_offset;
  4884.         attr->preedit_area.y = gui.border_offset;
  4885.         attr->preedit_area.width = width - 2*gui.border_offset;
  4886.         attr->preedit_area.height = height - 2*gui.border_offset;
  4887.         attr->preedit_fontset = gui.fontset;
  4888.         }
  4889.     }
  4890.  
  4891.     if ((xim_input_style & (int)GDK_IM_STATUS_MASK)
  4892.                            == (int)GDK_IM_STATUS_AREA)
  4893.     {
  4894.         if (gui.fontset == NOFONTSET
  4895.             || gui.fontset->type != GDK_FONT_FONTSET)
  4896.         {
  4897.         EMSG(_(e_overthespot));
  4898.         }
  4899.         else
  4900.         {
  4901.         gdk_window_get_size(gui.mainwin->window, &width, &height);
  4902.         attrmask |= (int)GDK_IC_STATUS_AREA_REQ;
  4903.         attr->status_area.x = 0;
  4904.         attr->status_area.y = height - gui.char_height - 1;
  4905.         attr->status_area.width = width;
  4906.         attr->status_area.height = gui.char_height;
  4907.         attr->status_fontset = gui.fontset;
  4908.         }
  4909.     }
  4910.     else if ((xim_input_style & (int)GDK_IM_STATUS_MASK)
  4911.                           == (int)GDK_IM_STATUS_CALLBACKS)
  4912.     {
  4913.         /* FIXME */
  4914.     }
  4915. #endif
  4916.  
  4917.     xic = gdk_ic_new(attr, (GdkICAttributesType)attrmask);
  4918.  
  4919.     if (xic == NULL)
  4920.         EMSG(_(e_xim));
  4921.     else
  4922.     {
  4923.         mask = (int)gdk_window_get_events(widget->window);
  4924.         mask |= (int)gdk_ic_get_events(xic);
  4925.         gdk_window_set_events(widget->window, (GdkEventMask)mask);
  4926.         if (xim_input_style & (int)GDK_IM_PREEDIT_CALLBACKS)
  4927.         preedit_callback_setup(xic);
  4928.         reset_state_setup(xic);
  4929.     }
  4930.     }
  4931. }
  4932.  
  4933.     void
  4934. im_shutdown(void)
  4935. {
  4936.     if (xic != NULL)
  4937.     {
  4938.     gdk_im_end();
  4939.     gdk_ic_destroy(xic);
  4940.     xic = NULL;
  4941.     }
  4942.     xim_is_active = FALSE;
  4943.     xim_preediting = FALSE;
  4944.     preedit_start_col = MAXCOL;
  4945. }
  4946.  
  4947. #endif /* FEAT_GUI_GTK */
  4948.  
  4949.     int
  4950. xim_get_status_area_height()
  4951. {
  4952. #ifdef FEAT_GUI_GTK
  4953.     if (xim_input_style & (int)GDK_IM_STATUS_AREA)
  4954.     return gui.char_height;
  4955. #else
  4956.     if (status_area_enabled)
  4957.     return gui.char_height;
  4958. #endif
  4959.     return 0;
  4960. }
  4961.  
  4962. /*
  4963.  * Get IM status.  When IM is on, return TRUE.  Else return FALSE.
  4964.  * FIXME: This doesn't work correctly: Having focus doesn't always mean XIM is
  4965.  * active, when not having focus XIM may still be active (e.g., when using a
  4966.  * tear-off menu item).
  4967.  */
  4968.     int
  4969. im_get_status()
  4970. {
  4971. #ifdef FEAT_GUI_GTK
  4972.     if (xim_input_style & (int)GDK_IM_PREEDIT_CALLBACKS)
  4973.     return xim_preediting;
  4974. #endif
  4975.     return xim_has_focus;
  4976. }
  4977.  
  4978. # endif /* !HAVE_GTK2 */
  4979. #endif /* FEAT_XIM */
  4980.  
  4981. #if defined(FEAT_MBYTE) || defined(PROTO)
  4982.  
  4983. /*
  4984.  * Setup "vcp" for conversion from "from" to "to".
  4985.  * The names must have been made canonical with enc_canonize().
  4986.  * vcp->vc_type must have been initialized to CONV_NONE.
  4987.  * Note: cannot be used for conversion from/to ucs-2 and ucs-4 (will use utf-8
  4988.  * instead).
  4989.  * Return FAIL when conversion is not supported, OK otherwise.
  4990.  */
  4991.     int
  4992. convert_setup(vcp, from, to)
  4993.     vimconv_T    *vcp;
  4994.     char_u    *from;
  4995.     char_u    *to;
  4996. {
  4997.     int        from_prop;
  4998.     int        to_prop;
  4999.  
  5000.     /* Reset to no conversion. */
  5001. # ifdef USE_ICONV
  5002.     if (vcp->vc_type == CONV_ICONV && vcp->vc_fd != (iconv_t)-1)
  5003.     iconv_close(vcp->vc_fd);
  5004. # endif
  5005.     vcp->vc_type = CONV_NONE;
  5006.     vcp->vc_factor = 1;
  5007.  
  5008.     /* No conversion when one of the names is empty or they are equal. */
  5009.     if (from == NULL || *from == NUL || to == NULL || *to == NUL
  5010.                              || STRCMP(from, to) == 0)
  5011.     return OK;
  5012.  
  5013.     from_prop = enc_canon_props(from);
  5014.     to_prop = enc_canon_props(to);
  5015.     if ((from_prop & ENC_LATIN1) && (to_prop & ENC_UNICODE))
  5016.     {
  5017.     /* Internal latin1 -> utf-8 conversion. */
  5018.     vcp->vc_type = CONV_TO_UTF8;
  5019.     vcp->vc_factor = 2;    /* up to twice as long */
  5020.     }
  5021.     else if ((from_prop & ENC_UNICODE) && (to_prop & ENC_LATIN1))
  5022.     {
  5023.     /* Internal utf-8 -> latin1 conversion. */
  5024.     vcp->vc_type = CONV_TO_LATIN1;
  5025.     }
  5026. #ifdef WIN3264
  5027.     /* Win32-specific codepage <-> codepage conversion without iconv. */
  5028.     else if (((from_prop & ENC_UNICODE) || encname2codepage(from) > 0)
  5029.         && ((to_prop & ENC_UNICODE) || encname2codepage(to) > 0))
  5030.     {
  5031.     vcp->vc_type = CONV_CODEPAGE;
  5032.     vcp->vc_factor = 2;    /* up to twice as long */
  5033.     vcp->vc_cpfrom = (from_prop & ENC_UNICODE) ? 0 : encname2codepage(from);
  5034.     vcp->vc_cpto = (to_prop & ENC_UNICODE) ? 0 : encname2codepage(to);
  5035.     }
  5036. #endif
  5037. # ifdef USE_ICONV
  5038.     else
  5039.     {
  5040.     /* Use iconv() for conversion. */
  5041.     vcp->vc_fd = (iconv_t)my_iconv_open(
  5042.         (to_prop & ENC_UNICODE) ? (char_u *)"utf-8" : to,
  5043.         (from_prop & ENC_UNICODE) ? (char_u *)"utf-8" : from);
  5044.     if (vcp->vc_fd != (iconv_t)-1)
  5045.     {
  5046.         vcp->vc_type = CONV_ICONV;
  5047.         vcp->vc_factor = 4;    /* could be longer too... */
  5048.     }
  5049.     }
  5050. # endif
  5051.     if (vcp->vc_type == CONV_NONE)
  5052.     return FAIL;
  5053.     return OK;
  5054. }
  5055.  
  5056. /*
  5057.  * Do conversion on typed input characters in-place.
  5058.  * The input and output are not NUL terminated!
  5059.  * Returns the length after conversion.
  5060.  */
  5061.     int
  5062. convert_input(ptr, len, maxlen)
  5063.     char_u    *ptr;
  5064.     int        len;
  5065.     int        maxlen;
  5066. {
  5067.     char_u    *d;
  5068.     int        dlen = len;
  5069.  
  5070.     d = string_convert(&input_conv, ptr, &dlen);
  5071.     if (d != NULL)
  5072.     {
  5073.     if (dlen <= maxlen)
  5074.         mch_memmove(ptr, d, dlen);
  5075.     else
  5076.         dlen = len;        /* result is too long, keep the unconverted text */
  5077.     vim_free(d);
  5078.     }
  5079.     return dlen;
  5080. }
  5081.  
  5082. /*
  5083.  * Convert text "ptr[*lenp]" according to "vcp".
  5084.  * Returns the result in allocated memory and sets "*lenp".
  5085.  * When "lenp" is NULL, use NUL terminated strings.
  5086.  * When something goes wrong, NULL is returned and "*lenp" is unchanged.
  5087.  */
  5088.     char_u *
  5089. string_convert(vcp, ptr, lenp)
  5090.     vimconv_T    *vcp;
  5091.     char_u    *ptr;
  5092.     int        *lenp;
  5093. {
  5094.     char_u    *retval = NULL;
  5095.     char_u    *d;
  5096.     int        len;
  5097.     int        i;
  5098.     int        l;
  5099.     int        c;
  5100.  
  5101.     if (lenp == NULL)
  5102.     len = (int)STRLEN(ptr);
  5103.     else
  5104.     len = *lenp;
  5105.     if (len == 0)
  5106.     return vim_strsave((char_u *)"");
  5107.  
  5108.     switch (vcp->vc_type)
  5109.     {
  5110.     case CONV_TO_UTF8:    /* latin1 to utf-8 conversion */
  5111.         retval = alloc(len * 2 + 1);
  5112.         if (retval == NULL)
  5113.         break;
  5114.         d = retval;
  5115.         for (i = 0; i < len; ++i)
  5116.         {
  5117.         if (ptr[i] < 0x80)
  5118.             *d++ = ptr[i];
  5119.         else
  5120.         {
  5121.             *d++ = 0xc0 + ((unsigned)ptr[i] >> 6);
  5122.             *d++ = 0x80 + (ptr[i] & 0x3f);
  5123.         }
  5124.         }
  5125.         *d = NUL;
  5126.         if (lenp != NULL)
  5127.         *lenp = (int)(d - retval);
  5128.         break;
  5129.  
  5130.     case CONV_TO_LATIN1:    /* utf-8 to latin1 conversion */
  5131.         retval = alloc(len + 1);
  5132.         if (retval == NULL)
  5133.         break;
  5134.         d = retval;
  5135.         for (i = 0; i < len; ++i)
  5136.         {
  5137.         l = utf_ptr2len_check(ptr + i);
  5138.         if (l <= 1)
  5139.             *d++ = ptr[i];
  5140.         else
  5141.         {
  5142.             c = utf_ptr2char(ptr + i);
  5143.             if (!utf_iscomposing(c))    /* skip composing chars */
  5144.             {
  5145.             if (c < 0x100)
  5146.                 *d++ = c;
  5147.             else
  5148.             {
  5149.                 *d++ = 0xbf;
  5150.                 if (utf_char2cells(c) > 1)
  5151.                 *d++ = '?';
  5152.             }
  5153.             }
  5154.             i += l - 1;
  5155.         }
  5156.         }
  5157.         *d = NUL;
  5158.         if (lenp != NULL)
  5159.         *lenp = (int)(d - retval);
  5160.         break;
  5161.  
  5162. # ifdef USE_ICONV
  5163.     case CONV_ICONV:    /* conversion with output_conv.vc_fd */
  5164.         retval = iconv_string(vcp->vc_fd, ptr, len);
  5165.         if (retval != NULL && lenp != NULL)
  5166.         *lenp = (int)STRLEN(retval);
  5167.         break;
  5168. # endif
  5169. # ifdef WIN3264
  5170.     case CONV_CODEPAGE:        /* codepage -> codepage */
  5171.     {
  5172.         int        retlen;
  5173.         int        tmp_len;
  5174.         short_u    *tmp;
  5175.  
  5176.         /* 1. codepage/UTF-8  ->  ucs-2. */
  5177.         if (vcp->vc_cpfrom == 0)
  5178.         tmp_len = utf8_to_ucs2(ptr, len, NULL);
  5179.         else
  5180.         tmp_len = MultiByteToWideChar(vcp->vc_cpfrom, 0,
  5181.                                   ptr, len, 0, 0);
  5182.         tmp = (short_u *)alloc(sizeof(short_u) * tmp_len);
  5183.         if (tmp == NULL)
  5184.         break;
  5185.         if (vcp->vc_cpfrom == 0)
  5186.         utf8_to_ucs2(ptr, len, tmp);
  5187.         else
  5188.         MultiByteToWideChar(vcp->vc_cpfrom, 0, ptr, len, tmp, tmp_len);
  5189.  
  5190.         /* 2. ucs-2  ->  codepage/UTF-8. */
  5191.         if (vcp->vc_cpto == 0)
  5192.         retlen = ucs2_to_utf8(tmp, tmp_len, NULL);
  5193.         else
  5194.         retlen = WideCharToMultiByte(vcp->vc_cpto, 0,
  5195.                             tmp, tmp_len, 0, 0, 0, 0);
  5196.         retval = alloc(retlen + 1);
  5197.         if (retval != NULL)
  5198.         {
  5199.         if (vcp->vc_cpto == 0)
  5200.             ucs2_to_utf8(tmp, tmp_len, retval);
  5201.         else
  5202.             WideCharToMultiByte(vcp->vc_cpto, 0,
  5203.                       tmp, tmp_len, retval, retlen, 0, 0);
  5204.         retval[retlen] = NUL;
  5205.         if (lenp != NULL)
  5206.             *lenp = retlen;
  5207.         }
  5208.         vim_free(tmp);
  5209.         break;
  5210.     }
  5211. # endif
  5212.     }
  5213.  
  5214.     return retval;
  5215. }
  5216. #endif
  5217.