Mercurial > vim
diff src/os_mswin.c @ 4168:ff193256398a v7.3.836
updated for version 7.3.836
Problem: Clipboard does not work on Win32 when compiled with Cygwin.
Solution: Move the Win32 clipboard code to a separate file and use it when
building with os_unix.c. (Frodak Baksik, Ken Takata)
author | Bram Moolenaar <bram@vim.org> |
---|---|
date | Tue, 26 Feb 2013 14:56:42 +0100 |
parents | e6d8b44065bc |
children | 26e59a39fdd9 |
line wrap: on
line diff
--- a/src/os_mswin.c +++ b/src/os_mswin.c @@ -905,736 +905,6 @@ mch_libcall( } #endif -#if defined(FEAT_MBYTE) || defined(PROTO) -/* - * Convert an UTF-8 string to UTF-16. - * "instr[inlen]" is the input. "inlen" is in bytes. - * When "outstr" is NULL only return the number of UTF-16 words produced. - * Otherwise "outstr" must be a buffer of sufficient size. - * Returns the number of UTF-16 words produced. - */ - int -utf8_to_utf16(char_u *instr, int inlen, short_u *outstr, int *unconvlenp) -{ - int outlen = 0; - char_u *p = instr; - int todo = inlen; - int l; - int ch; - - while (todo > 0) - { - /* Only convert if we have a complete sequence. */ - l = utf_ptr2len_len(p, todo); - if (l > todo) - { - /* Return length of incomplete sequence. */ - if (unconvlenp != NULL) - *unconvlenp = todo; - break; - } - - ch = utf_ptr2char(p); - if (ch >= 0x10000) - { - /* non-BMP character, encoding with surrogate pairs */ - ++outlen; - if (outstr != NULL) - { - *outstr++ = (0xD800 - (0x10000 >> 10)) + (ch >> 10); - *outstr++ = 0xDC00 | (ch & 0x3FF); - } - } - else if (outstr != NULL) - *outstr++ = ch; - ++outlen; - p += l; - todo -= l; - } - - return outlen; -} - -/* - * Convert an UTF-16 string to UTF-8. - * The input is "instr[inlen]" with "inlen" in number of UTF-16 words. - * When "outstr" is NULL only return the required number of bytes. - * Otherwise "outstr" must be a buffer of sufficient size. - * Return the number of bytes produced. - */ - int -utf16_to_utf8(short_u *instr, int inlen, char_u *outstr) -{ - int outlen = 0; - int todo = inlen; - short_u *p = instr; - int l; - int ch, ch2; - - while (todo > 0) - { - ch = *p; - if (ch >= 0xD800 && ch <= 0xDBFF && todo > 1) - { - /* surrogate pairs handling */ - ch2 = p[1]; - if (ch2 >= 0xDC00 && ch2 <= 0xDFFF) - { - ch = ((ch - 0xD800) << 10) + (ch2 & 0x3FF) + 0x10000; - ++p; - --todo; - } - } - if (outstr != NULL) - { - l = utf_char2bytes(ch, outstr); - outstr += l; - } - else - l = utf_char2len(ch); - ++p; - outlen += l; - --todo; - } - - return outlen; -} - -/* - * Call MultiByteToWideChar() and allocate memory for the result. - * Returns the result in "*out[*outlen]" with an extra zero appended. - * "outlen" is in words. - */ - void -MultiByteToWideChar_alloc(UINT cp, DWORD flags, - LPCSTR in, int inlen, - LPWSTR *out, int *outlen) -{ - *outlen = MultiByteToWideChar(cp, flags, in, inlen, 0, 0); - /* Add one one word to avoid a zero-length alloc(). */ - *out = (LPWSTR)alloc(sizeof(WCHAR) * (*outlen + 1)); - if (*out != NULL) - { - MultiByteToWideChar(cp, flags, in, inlen, *out, *outlen); - (*out)[*outlen] = 0; - } -} - -/* - * Call WideCharToMultiByte() and allocate memory for the result. - * Returns the result in "*out[*outlen]" with an extra NUL appended. - */ - void -WideCharToMultiByte_alloc(UINT cp, DWORD flags, - LPCWSTR in, int inlen, - LPSTR *out, int *outlen, - LPCSTR def, LPBOOL useddef) -{ - *outlen = WideCharToMultiByte(cp, flags, in, inlen, NULL, 0, def, useddef); - /* Add one one byte to avoid a zero-length alloc(). */ - *out = alloc((unsigned)*outlen + 1); - if (*out != NULL) - { - WideCharToMultiByte(cp, flags, in, inlen, *out, *outlen, def, useddef); - (*out)[*outlen] = 0; - } -} - -#endif /* FEAT_MBYTE */ - -#ifdef FEAT_CLIPBOARD -/* - * Clipboard stuff, for cutting and pasting text to other windows. - */ - -/* Type used for the clipboard type of Vim's data. */ -typedef struct -{ - int type; /* MCHAR, MBLOCK or MLINE */ - int txtlen; /* length of CF_TEXT in bytes */ - int ucslen; /* length of CF_UNICODETEXT in words */ - int rawlen; /* length of clip_star.format_raw, including encoding, - excluding terminating NUL */ -} VimClipType_t; - -/* - * Make vim the owner of the current selection. Return OK upon success. - */ -/*ARGSUSED*/ - int -clip_mch_own_selection(VimClipboard *cbd) -{ - /* - * Never actually own the clipboard. If another application sets the - * clipboard, we don't want to think that we still own it. - */ - return FAIL; -} - -/* - * Make vim NOT the owner of the current selection. - */ -/*ARGSUSED*/ - void -clip_mch_lose_selection(VimClipboard *cbd) -{ - /* Nothing needs to be done here */ -} - -/* - * Copy "str[*size]" into allocated memory, changing CR-NL to NL. - * Return the allocated result and the size in "*size". - * Returns NULL when out of memory. - */ - static char_u * -crnl_to_nl(const char_u *str, int *size) -{ - int pos = 0; - int str_len = *size; - char_u *ret; - char_u *retp; - - /* Avoid allocating zero bytes, it generates an error message. */ - ret = lalloc((long_u)(str_len == 0 ? 1 : str_len), TRUE); - if (ret != NULL) - { - retp = ret; - for (pos = 0; pos < str_len; ++pos) - { - if (str[pos] == '\r' && str[pos + 1] == '\n') - { - ++pos; - --(*size); - } - *retp++ = str[pos]; - } - } - - return ret; -} - -/* - * Wait for another process to Close the Clipboard. - * Returns TRUE for success. - */ - static int -vim_open_clipboard(void) -{ - int delay = 10; - - while (!OpenClipboard(NULL)) - { - if (delay > 500) - return FALSE; /* waited too long, give up */ - Sleep(delay); - delay *= 2; /* wait for 10, 20, 40, 80, etc. msec */ - } - return TRUE; -} - -/* - * Get the current selection and put it in the clipboard register. - * - * NOTE: Must use GlobalLock/Unlock here to ensure Win32s compatibility. - * On NT/W95 the clipboard data is a fixed global memory object and - * so its handle = its pointer. - * On Win32s, however, co-operation with the Win16 system means that - * the clipboard data is moveable and its handle is not a pointer at all, - * so we can't just cast the return value of GetClipboardData to (char_u*). - * <VN> - */ - void -clip_mch_request_selection(VimClipboard *cbd) -{ - VimClipType_t metadata = { -1, -1, -1, -1 }; - HGLOBAL hMem = NULL; - char_u *str = NULL; -#if defined(FEAT_MBYTE) && defined(WIN3264) - char_u *to_free = NULL; -#endif -#ifdef FEAT_MBYTE - HGLOBAL rawh = NULL; -#endif - int str_size = 0; - int maxlen; - size_t n; - - /* - * Don't pass GetActiveWindow() as an argument to OpenClipboard() because - * then we can't paste back into the same window for some reason - webb. - */ - if (!vim_open_clipboard()) - return; - - /* Check for vim's own clipboard format first. This only gets the type of - * the data, still need to use CF_UNICODETEXT or CF_TEXT for the text. */ - if (IsClipboardFormatAvailable(cbd->format)) - { - VimClipType_t *meta_p; - HGLOBAL meta_h; - - /* We have metadata on the clipboard; try to get it. */ - if ((meta_h = GetClipboardData(cbd->format)) != NULL - && (meta_p = (VimClipType_t *)GlobalLock(meta_h)) != NULL) - { - /* The size of "VimClipType_t" changed, "rawlen" was added later. - * Only copy what is available for backwards compatibility. */ - n = sizeof(VimClipType_t); - if (GlobalSize(meta_h) < n) - n = GlobalSize(meta_h); - memcpy(&metadata, meta_p, n); - GlobalUnlock(meta_h); - } - } - -#ifdef FEAT_MBYTE - /* Check for Vim's raw clipboard format first. This is used without - * conversion, but only if 'encoding' matches. */ - if (IsClipboardFormatAvailable(cbd->format_raw) - && metadata.rawlen > (int)STRLEN(p_enc)) - { - /* We have raw data on the clipboard; try to get it. */ - if ((rawh = GetClipboardData(cbd->format_raw)) != NULL) - { - char_u *rawp; - - rawp = (char_u *)GlobalLock(rawh); - if (rawp != NULL && STRCMP(p_enc, rawp) == 0) - { - n = STRLEN(p_enc) + 1; - str = rawp + n; - str_size = (int)(metadata.rawlen - n); - } - else - { - GlobalUnlock(rawh); - rawh = NULL; - } - } - } - if (str == NULL) - { -#endif - -#if defined(FEAT_MBYTE) && defined(WIN3264) - /* Try to get the clipboard in Unicode if it's not an empty string. */ - if (IsClipboardFormatAvailable(CF_UNICODETEXT) && metadata.ucslen != 0) - { - HGLOBAL hMemW; - - if ((hMemW = GetClipboardData(CF_UNICODETEXT)) != NULL) - { - WCHAR *hMemWstr = (WCHAR *)GlobalLock(hMemW); - - /* Use the length of our metadata if possible, but limit it to the - * GlobalSize() for safety. */ - maxlen = (int)(GlobalSize(hMemW) / sizeof(WCHAR)); - if (metadata.ucslen >= 0) - { - if (metadata.ucslen > maxlen) - str_size = maxlen; - else - str_size = metadata.ucslen; - } - else - { - for (str_size = 0; str_size < maxlen; ++str_size) - if (hMemWstr[str_size] == NUL) - break; - } - to_free = str = utf16_to_enc((short_u *)hMemWstr, &str_size); - GlobalUnlock(hMemW); - } - } - else -#endif - /* Get the clipboard in the Active codepage. */ - if (IsClipboardFormatAvailable(CF_TEXT)) - { - if ((hMem = GetClipboardData(CF_TEXT)) != NULL) - { - str = (char_u *)GlobalLock(hMem); - - /* The length is either what our metadata says or the strlen(). - * But limit it to the GlobalSize() for safety. */ - maxlen = (int)GlobalSize(hMem); - if (metadata.txtlen >= 0) - { - if (metadata.txtlen > maxlen) - str_size = maxlen; - else - str_size = metadata.txtlen; - } - else - { - for (str_size = 0; str_size < maxlen; ++str_size) - if (str[str_size] == NUL) - break; - } - -# if defined(FEAT_MBYTE) && defined(WIN3264) - /* The text is in the active codepage. Convert to 'encoding', - * going through UTF-16. */ - acp_to_enc(str, str_size, &to_free, &maxlen); - if (to_free != NULL) - { - str_size = maxlen; - str = to_free; - } -# endif - } - } -#ifdef FEAT_MBYTE - } -#endif - - if (str != NULL && *str != NUL) - { - char_u *temp_clipboard; - - /* If the type is not known detect it. */ - if (metadata.type == -1) - metadata.type = MAUTO; - - /* Translate <CR><NL> into <NL>. */ - temp_clipboard = crnl_to_nl(str, &str_size); - if (temp_clipboard != NULL) - { - clip_yank_selection(metadata.type, temp_clipboard, str_size, cbd); - vim_free(temp_clipboard); - } - } - - /* unlock the global object */ - if (hMem != NULL) - GlobalUnlock(hMem); -#ifdef FEAT_MBYTE - if (rawh != NULL) - GlobalUnlock(rawh); -#endif - CloseClipboard(); -#if defined(FEAT_MBYTE) && defined(WIN3264) - vim_free(to_free); -#endif -} - -/* - * Send the current selection to the clipboard. - */ - void -clip_mch_set_selection(VimClipboard *cbd) -{ - char_u *str = NULL; - VimClipType_t metadata; - long_u txtlen; - HGLOBAL hMemRaw = NULL; - HGLOBAL hMem = NULL; - HGLOBAL hMemVim = NULL; -# if defined(FEAT_MBYTE) && defined(WIN3264) - HGLOBAL hMemW = NULL; -# endif - - /* If the '*' register isn't already filled in, fill it in now */ - cbd->owned = TRUE; - clip_get_selection(cbd); - cbd->owned = FALSE; - - /* Get the text to be put on the clipboard, with CR-LF. */ - metadata.type = clip_convert_selection(&str, &txtlen, cbd); - if (metadata.type < 0) - return; - metadata.txtlen = (int)txtlen; - metadata.ucslen = 0; - metadata.rawlen = 0; - -#ifdef FEAT_MBYTE - /* Always set the raw bytes: 'encoding', NUL and the text. This is used - * when copy/paste from/to Vim with the same 'encoding', so that illegal - * bytes can also be copied and no conversion is needed. */ - { - LPSTR lpszMemRaw; - - metadata.rawlen = (int)(txtlen + STRLEN(p_enc) + 1); - hMemRaw = (LPSTR)GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, - metadata.rawlen + 1); - lpszMemRaw = (LPSTR)GlobalLock(hMemRaw); - if (lpszMemRaw != NULL) - { - STRCPY(lpszMemRaw, p_enc); - memcpy(lpszMemRaw + STRLEN(p_enc) + 1, str, txtlen + 1); - GlobalUnlock(hMemRaw); - } - else - metadata.rawlen = 0; - } -#endif - -# if defined(FEAT_MBYTE) && defined(WIN3264) - { - WCHAR *out; - int len = metadata.txtlen; - - /* Convert the text to UTF-16. This is put on the clipboard as - * CF_UNICODETEXT. */ - out = (WCHAR *)enc_to_utf16(str, &len); - if (out != NULL) - { - WCHAR *lpszMemW; - - /* Convert the text for CF_TEXT to Active codepage. Otherwise it's - * p_enc, which has no relation to the Active codepage. */ - metadata.txtlen = WideCharToMultiByte(GetACP(), 0, out, len, - NULL, 0, 0, 0); - vim_free(str); - str = (char_u *)alloc((unsigned)(metadata.txtlen == 0 ? 1 - : metadata.txtlen)); - if (str == NULL) - { - vim_free(out); - return; /* out of memory */ - } - WideCharToMultiByte(GetACP(), 0, out, len, - str, metadata.txtlen, 0, 0); - - /* Allocate memory for the UTF-16 text, add one NUL word to - * terminate the string. */ - hMemW = (LPSTR)GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, - (len + 1) * sizeof(WCHAR)); - lpszMemW = (WCHAR *)GlobalLock(hMemW); - if (lpszMemW != NULL) - { - memcpy(lpszMemW, out, len * sizeof(WCHAR)); - lpszMemW[len] = NUL; - GlobalUnlock(hMemW); - } - vim_free(out); - metadata.ucslen = len; - } - } -# endif - - /* Allocate memory for the text, add one NUL byte to terminate the string. - */ - hMem = GlobalAlloc(GMEM_MOVEABLE | GMEM_DDESHARE, metadata.txtlen + 1); - { - LPSTR lpszMem = (LPSTR)GlobalLock(hMem); - - if (lpszMem) - { - vim_strncpy(lpszMem, str, metadata.txtlen); - GlobalUnlock(hMem); - } - } - - /* Set up metadata: */ - { - VimClipType_t *lpszMemVim = NULL; - - hMemVim = GlobalAlloc(GMEM_MOVEABLE|GMEM_DDESHARE, - sizeof(VimClipType_t)); - lpszMemVim = (VimClipType_t *)GlobalLock(hMemVim); - memcpy(lpszMemVim, &metadata, sizeof(metadata)); - GlobalUnlock(hMemVim); - } - - /* - * Open the clipboard, clear it and put our text on it. - * Always set our Vim format. Put Unicode and plain text on it. - * - * Don't pass GetActiveWindow() as an argument to OpenClipboard() - * because then we can't paste back into the same window for some - * reason - webb. - */ - if (vim_open_clipboard()) - { - if (EmptyClipboard()) - { - SetClipboardData(cbd->format, hMemVim); - hMemVim = 0; -# if defined(FEAT_MBYTE) && defined(WIN3264) - if (hMemW != NULL) - { - if (SetClipboardData(CF_UNICODETEXT, hMemW) != NULL) - hMemW = NULL; - } -# endif - /* Always use CF_TEXT. On Win98 Notepad won't obtain the - * CF_UNICODETEXT text, only CF_TEXT. */ - SetClipboardData(CF_TEXT, hMem); - hMem = 0; - } - CloseClipboard(); - } - - vim_free(str); - /* Free any allocations we didn't give to the clipboard: */ - if (hMemRaw) - GlobalFree(hMemRaw); - if (hMem) - GlobalFree(hMem); -# if defined(FEAT_MBYTE) && defined(WIN3264) - if (hMemW) - GlobalFree(hMemW); -# endif - if (hMemVim) - GlobalFree(hMemVim); -} - -#endif /* FEAT_CLIPBOARD */ - -#if defined(FEAT_MBYTE) || defined(PROTO) -/* - * Note: the following two functions are only guaranteed to work when using - * valid MS-Windows codepages or when iconv() is available. - */ - -/* - * Convert "str" from 'encoding' to UTF-16. - * Input in "str" with length "*lenp". When "lenp" is NULL, use strlen(). - * Output is returned as an allocated string. "*lenp" is set to the length of - * the result. A trailing NUL is always added. - * Returns NULL when out of memory. - */ - short_u * -enc_to_utf16(char_u *str, int *lenp) -{ - vimconv_T conv; - WCHAR *ret; - char_u *allocbuf = NULL; - int len_loc; - int length; - - if (lenp == NULL) - { - len_loc = (int)STRLEN(str) + 1; - lenp = &len_loc; - } - - if (enc_codepage > 0) - { - /* We can do any CP### -> UTF-16 in one pass, and we can do it - * without iconv() (convert_* may need iconv). */ - MultiByteToWideChar_alloc(enc_codepage, 0, str, *lenp, &ret, &length); - } - else - { - /* Use "latin1" by default, we might be called before we have p_enc - * set up. Convert to utf-8 first, works better with iconv(). Does - * nothing if 'encoding' is "utf-8". */ - conv.vc_type = CONV_NONE; - if (convert_setup(&conv, p_enc ? p_enc : (char_u *)"latin1", - (char_u *)"utf-8") == FAIL) - return NULL; - if (conv.vc_type != CONV_NONE) - { - str = allocbuf = string_convert(&conv, str, lenp); - if (str == NULL) - return NULL; - } - convert_setup(&conv, NULL, NULL); - - length = utf8_to_utf16(str, *lenp, NULL, NULL); - ret = (WCHAR *)alloc((unsigned)((length + 1) * sizeof(WCHAR))); - if (ret != NULL) - { - utf8_to_utf16(str, *lenp, (short_u *)ret, NULL); - ret[length] = 0; - } - - vim_free(allocbuf); - } - - *lenp = length; - return (short_u *)ret; -} - -/* - * Convert an UTF-16 string to 'encoding'. - * Input in "str" with length (counted in wide characters) "*lenp". When - * "lenp" is NULL, use wcslen(). - * Output is returned as an allocated string. If "*lenp" is not NULL it is - * set to the length of the result. - * Returns NULL when out of memory. - */ - char_u * -utf16_to_enc(short_u *str, int *lenp) -{ - vimconv_T conv; - char_u *utf8_str = NULL, *enc_str = NULL; - int len_loc; - - if (lenp == NULL) - { - len_loc = (int)wcslen(str) + 1; - lenp = &len_loc; - } - - if (enc_codepage > 0) - { - /* We can do any UTF-16 -> CP### in one pass. */ - int length; - - WideCharToMultiByte_alloc(enc_codepage, 0, str, *lenp, - (LPSTR *)&enc_str, &length, 0, 0); - *lenp = length; - return enc_str; - } - - /* Avoid allocating zero bytes, it generates an error message. */ - utf8_str = alloc(utf16_to_utf8(str, *lenp == 0 ? 1 : *lenp, NULL)); - if (utf8_str != NULL) - { - *lenp = utf16_to_utf8(str, *lenp, utf8_str); - - /* We might be called before we have p_enc set up. */ - conv.vc_type = CONV_NONE; - convert_setup(&conv, (char_u *)"utf-8", - p_enc? p_enc: (char_u *)"latin1"); - if (conv.vc_type == CONV_NONE) - { - /* p_enc is utf-8, so we're done. */ - enc_str = utf8_str; - } - else - { - enc_str = string_convert(&conv, utf8_str, lenp); - vim_free(utf8_str); - } - - convert_setup(&conv, NULL, NULL); - } - - return enc_str; -} -#endif /* FEAT_MBYTE */ - -#if (defined(FEAT_MBYTE) && defined(WIN3264)) || defined(PROTO) -/* - * Convert from the active codepage to 'encoding'. - * Input is "str[str_size]". - * The result is in allocated memory: "out[outlen]". With terminating NUL. - */ - void -acp_to_enc(str, str_size, out, outlen) - char_u *str; - int str_size; - char_u **out; - int *outlen; - -{ - LPWSTR widestr; - - MultiByteToWideChar_alloc(GetACP(), 0, str, str_size, &widestr, outlen); - if (widestr != NULL) - { - ++*outlen; /* Include the 0 after the string */ - *out = utf16_to_enc((short_u *)widestr, outlen); - vim_free(widestr); - } -} -#endif - - /* * Debugging helper: expose the MCH_WRITE_DUMP stuff to other modules */