# HG changeset patch # User Bram Moolenaar # Date 1361887002 -3600 # Node ID ff193256398a81a520b44c67d661eee36c64ee95 # Parent 71e95ad234a65a960b4e43f352ce66420ea40521 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) diff --git a/src/Make_bc5.mak b/src/Make_bc5.mak --- a/src/Make_bc5.mak +++ b/src/Make_bc5.mak @@ -694,7 +694,7 @@ vimobj = $(vimobj) \ !if ($(OSTYPE)==WIN32) vimobj = $(vimobj) \ - $(OBJDIR)\os_win32.obj $(OBJDIR)\os_mswin.obj + $(OBJDIR)\os_win32.obj $(OBJDIR)\os_mswin.obj $(OBJDIR)\winclip.obj !elif ($(OSTYPE)==DOS16) vimobj = $(vimobj) \ $(OBJDIR)\os_msdos.obj diff --git a/src/Make_cyg.mak b/src/Make_cyg.mak --- a/src/Make_cyg.mak +++ b/src/Make_cyg.mak @@ -547,6 +547,7 @@ OBJ = \ $(OUTDIR)/option.o \ $(OUTDIR)/os_win32.o \ $(OUTDIR)/os_mswin.o \ + $(OUTDIR)/winclip.o \ $(OUTDIR)/pathdef.o \ $(OUTDIR)/popupmnu.o \ $(OUTDIR)/quickfix.o \ diff --git a/src/Make_ivc.mak b/src/Make_ivc.mak --- a/src/Make_ivc.mak +++ b/src/Make_ivc.mak @@ -241,6 +241,7 @@ LINK32_OBJS= \ "$(INTDIR)/ops.obj" \ "$(INTDIR)/option.obj" \ "$(INTDIR)/os_mswin.obj" \ + "$(INTDIR)/winclip.obj" \ "$(INTDIR)/os_win32.obj" \ "$(INTDIR)/popupmnu.obj" \ "$(INTDIR)/quickfix.obj" \ @@ -600,6 +601,10 @@ SOURCE=.\os_mswin.c # End Source File # Begin Source File +SOURCE=.\winclip.c +# End Source File +# Begin Source File + SOURCE=.\os_win32.c # End Source File # Begin Source File diff --git a/src/Make_ming.mak b/src/Make_ming.mak --- a/src/Make_ming.mak +++ b/src/Make_ming.mak @@ -523,6 +523,7 @@ OBJ = \ $(OUTDIR)/option.o \ $(OUTDIR)/os_win32.o \ $(OUTDIR)/os_mswin.o \ + $(OUTDIR)/winclip.o \ $(OUTDIR)/pathdef.o \ $(OUTDIR)/popupmnu.o \ $(OUTDIR)/quickfix.o \ diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak --- a/src/Make_mvc.mak +++ b/src/Make_mvc.mak @@ -543,6 +543,7 @@ OBJ = \ $(OUTDIR)\ops.obj \ $(OUTDIR)\option.obj \ $(OUTDIR)\os_mswin.obj \ + $(OUTDIR)\winclip.obj \ $(OUTDIR)\os_win32.obj \ $(OUTDIR)\pathdef.obj \ $(OUTDIR)\popupmnu.obj \ @@ -1149,6 +1150,8 @@ mzscheme_base.c: $(OUTDIR)/os_mswin.obj: $(OUTDIR) os_mswin.c $(INCL) +$(OUTDIR)/winclip.obj: $(OUTDIR) winclip.c $(INCL) + $(OUTDIR)/os_win32.obj: $(OUTDIR) os_win32.c $(INCL) os_win32.h $(OUTDIR)/os_w32exe.obj: $(OUTDIR) os_w32exe.c $(INCL) @@ -1256,6 +1259,7 @@ proto.h: \ proto/ops.pro \ proto/option.pro \ proto/os_mswin.pro \ + proto/winclip.pro \ proto/os_win32.pro \ proto/popupmnu.pro \ proto/quickfix.pro \ diff --git a/src/Make_w16.mak b/src/Make_w16.mak --- a/src/Make_w16.mak +++ b/src/Make_w16.mak @@ -107,6 +107,7 @@ ObjFiles = \ $(INTDIR)\os_win16.obj\ $(INTDIR)\os_msdos.obj\ $(INTDIR)\os_mswin.obj\ + $(INTDIR)\winclip.obj\ $(INTDIR)\popupmnu.obj\ $(INTDIR)\quickfix.obj\ $(INTDIR)\regexp.obj\ diff --git a/src/Makefile b/src/Makefile --- a/src/Makefile +++ b/src/Makefile @@ -1638,7 +1638,7 @@ PRO_AUTO = \ RSRC_DIR = os_mac_rsrc PRO_MANUAL = os_amiga.pro os_msdos.pro os_win16.pro os_win32.pro \ - os_mswin.pro os_beos.pro os_vms.pro $(PERL_PRO) + os_mswin.pro winclip.pro os_beos.pro os_vms.pro $(PERL_PRO) # Default target is making the executable and tools all: $(VIMTARGET) $(TOOLS) languages $(GUI_BUNDLE) @@ -1792,6 +1792,10 @@ os_mswin.pro: os_mswin.c $(CPROTO) -DWIN16 -DWIN32 -UHAVE_CONFIG_H $< > proto/$@ echo "/* vim: set ft=c : */" >> proto/$@ +winclip.pro: winclip.c + $(CPROTO) -DWIN16 -DWIN32 -UHAVE_CONFIG_H $< > proto/$@ + echo "/* vim: set ft=c : */" >> proto/$@ + os_beos.pro: os_beos.c $(CPROTO) -D__BEOS__ -UHAVE_CONFIG_H $< > proto/$@ echo "/* vim: set ft=c : */" >> proto/$@ @@ -2642,6 +2646,12 @@ objects/os_mac_conv.o: os_mac_conv.c objects/os_unix.o: os_unix.c $(CCC) -o $@ os_unix.c +objects/os_mswin.o: os_mswin.c + $(CCC) -o $@ os_mswin.c + +objects/winclip.o: winclip.c + $(CCC) -o $@ winclip.c + objects/pathdef.o: auto/pathdef.c $(CCC) -o $@ auto/pathdef.c @@ -2970,6 +2980,10 @@ objects/version.o: version.c vim.h auto/ ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \ gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h globals.h farsi.h \ arabic.h version.h +objects/winclip.o: winclip.c vimio.h vim.h auto/config.h feature.h os_unix.h \ + auto/osdef.h ascii.h keymap.h term.h macros.h option.h structs.h \ + regexp.h gui.h ex_cmds.h proto.h globals.h farsi.h arabic.h \ + proto/winclip.pro objects/window.o: window.c vim.h auto/config.h feature.h os_unix.h auto/osdef.h \ ascii.h keymap.h term.h macros.h option.h structs.h regexp.h gui.h \ gui_beval.h proto/gui_beval.pro ex_cmds.h proto.h globals.h farsi.h \ diff --git a/src/auto/configure b/src/auto/configure --- a/src/auto/configure +++ b/src/auto/configure @@ -8846,6 +8846,27 @@ fi +{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CYGWIN environment" >&5 +$as_echo_n "checking for CYGWIN environment... " >&6; } +case `uname` in + CYGWIN*) CYGWIN=yes; { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + { $as_echo "$as_me:${as_lineno-$LINENO}: checking for CYGWIN clipboard support" >&5 +$as_echo_n "checking for CYGWIN clipboard support... " >&6; } + if test "x$with_x" = "xno" ; then + OS_EXTRA_SRC=winclip.c; OS_EXTRA_OBJ=objects/winclip.o + { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5 +$as_echo "yes" >&6; } + $as_echo "#define FEAT_CYGWIN_WIN32_CLIPBOARD 1" >>confdefs.h + + else + { $as_echo "$as_me:${as_lineno-$LINENO}: result: no - using X11" >&5 +$as_echo "no - using X11" >&6; } + fi ;; + + *) CYGWIN=no; { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5 +$as_echo "no" >&6; };; +esac if test "$enable_hangulinput" = "yes"; then if test "x$GUITYPE" = "xNONE"; then diff --git a/src/config.h.in b/src/config.h.in --- a/src/config.h.in +++ b/src/config.h.in @@ -439,3 +439,6 @@ /* Define if fcntl()'s F_SETFD command knows about FD_CLOEXEC */ #undef HAVE_FD_CLOEXEC + +/* Define if you want Cygwin to use the WIN32 clipboard, not compatible with X11*/ +#undef FEAT_CYGWIN_WIN32_CLIPBOARD diff --git a/src/configure.in b/src/configure.in --- a/src/configure.in +++ b/src/configure.in @@ -2474,6 +2474,21 @@ dnl ------------------------------------ dnl end of GUI-checking dnl --------------------------------------------------------------------------- +dnl Check for Cygwin, which needs an extra source file if not using X11 +AC_MSG_CHECKING(for CYGWIN environment) +case `uname` in + CYGWIN*) CYGWIN=yes; AC_MSG_RESULT(yes) + AC_MSG_CHECKING(for CYGWIN clipboard support) + if test "x$with_x" = "xno" ; then + OS_EXTRA_SRC=winclip.c; OS_EXTRA_OBJ=objects/winclip.o + AC_MSG_RESULT(yes) + AC_DEFINE(FEAT_CYGWIN_WIN32_CLIPBOARD) + else + AC_MSG_RESULT(no - using X11) + fi ;; + + *) CYGWIN=no; AC_MSG_RESULT(no);; +esac dnl Only really enable hangul input when GUI and XFONTSET are available if test "$enable_hangulinput" = "yes"; then diff --git a/src/feature.h b/src/feature.h --- a/src/feature.h +++ b/src/feature.h @@ -1129,6 +1129,11 @@ * +xterm_clipboard Unix only: Include code for handling the clipboard * in an xterm like in the GUI. */ + +#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD +# define FEAT_CLIPBOARD +#endif + #ifdef FEAT_GUI # ifndef FEAT_CLIPBOARD # define FEAT_CLIPBOARD diff --git a/src/globals.h b/src/globals.h --- a/src/globals.h +++ b/src/globals.h @@ -802,7 +802,7 @@ EXTERN int enc_dbcs INIT(= 0); /* One o EXTERN int enc_unicode INIT(= 0); /* 2: UCS-2 or UTF-16, 4: UCS-4 */ EXTERN int enc_utf8 INIT(= FALSE); /* UTF-8 encoded Unicode */ EXTERN int enc_latin1like INIT(= TRUE); /* 'encoding' is latin1 comp. */ -# ifdef WIN3264 +# if defined(WIN3264) || defined(FEAT_CYGWIN_WIN32_CLIPBOARD) /* Codepage nr of 'encoding'. Negative means it's not been set yet, zero * means 'encoding' is not a valid codepage. */ EXTERN int enc_codepage INIT(= -1); diff --git a/src/mbyte.c b/src/mbyte.c --- a/src/mbyte.c +++ b/src/mbyte.c @@ -613,7 +613,7 @@ codepage_invalid: enc_dbcs = enc_dbcs_new; has_mbyte = (enc_dbcs != 0 || enc_utf8); -#ifdef WIN3264 +#if defined(WIN3264) || defined(FEAT_CYGWIN_WIN32_CLIPBOARD) enc_codepage = encname2codepage(p_enc); enc_latin9 = (STRCMP(p_enc, "iso-8859-15") == 0); #endif @@ -4089,7 +4089,7 @@ enc_locale() return enc_canonize((char_u *)buf); } -#if defined(WIN3264) || defined(PROTO) +#if defined(WIN3264) || defined(PROTO) || defined(FEAT_CYGWIN_WIN32_CLIPBOARD) /* * Convert an encoding name to an MS-Windows codepage. * Returns zero if no codepage can be figured out. diff --git a/src/os_mswin.c b/src/os_mswin.c --- 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*). - * - */ - 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 into . */ - 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 */ diff --git a/src/os_unix.c b/src/os_unix.c --- a/src/os_unix.c +++ b/src/os_unix.c @@ -61,6 +61,11 @@ static int selinux_enabled = -1; # include # include /* for cygwin_conv_to_posix_path() and/or * for cygwin_conv_path() */ +# ifdef FEAT_CYGWIN_WIN32_CLIPBOARD +# define WIN32_LEAN_AND_MEAN +# include +# include "winclip.pro" +# endif # endif #endif @@ -1223,6 +1228,9 @@ mch_init() #ifdef MACOS_CONVERT mac_conv_init(); #endif +#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD + win_clip_init(); +#endif } static void diff --git a/src/os_win32.c b/src/os_win32.c --- a/src/os_win32.c +++ b/src/os_win32.c @@ -1851,16 +1851,7 @@ mch_init(void) set_option_value((char_u *)"grepprg", 0, (char_u *)"grep -n", 0); #ifdef FEAT_CLIPBOARD - clip_init(TRUE); - - /* - * Vim's own clipboard format recognises whether the text is char, line, - * or rectangular block. Only useful for copying between two Vims. - * "VimClipboard" was used for previous versions, using the first - * character to specify MCHAR, MLINE or MBLOCK. - */ - clip_star.format = RegisterClipboardFormat("VimClipboard2"); - clip_star.format_raw = RegisterClipboardFormat("VimRawBytes"); + win_clip_init(); #endif } @@ -2345,16 +2336,7 @@ mch_init(void) #endif #ifdef FEAT_CLIPBOARD - clip_init(TRUE); - - /* - * Vim's own clipboard format recognises whether the text is char, line, or - * rectangular block. Only useful for copying between two Vims. - * "VimClipboard" was used for previous versions, using the first - * character to specify MCHAR, MLINE or MBLOCK. - */ - clip_star.format = RegisterClipboardFormat("VimClipboard2"); - clip_star.format_raw = RegisterClipboardFormat("VimRawBytes"); + win_clip_init(); #endif /* This will be NULL on anything but NT 4.0 */ diff --git a/src/proto.h b/src/proto.h --- a/src/proto.h +++ b/src/proto.h @@ -47,10 +47,12 @@ typedef int LPBOOL; # include "os_win16.pro" # include "os_mswin.pro" +# include "winclip.pro" # endif # ifdef WIN3264 # include "os_win32.pro" # include "os_mswin.pro" +# include "winclip.pro" # if (defined(__GNUC__) && !defined(__MINGW32__)) \ || (defined(__BORLANDC__) && __BORLANDC__ < 0x502) extern int _stricoll __ARGS((char *a, char *b)); diff --git a/src/proto/os_mswin.pro b/src/proto/os_mswin.pro --- a/src/proto/os_mswin.pro +++ b/src/proto/os_mswin.pro @@ -22,17 +22,6 @@ int mch_chdir __ARGS((char *path)); int can_end_termcap_mode __ARGS((int give_msg)); int mch_screenmode __ARGS((char_u *arg)); int mch_libcall __ARGS((char_u *libname, char_u *funcname, char_u *argstring, int argint, char_u **string_result, int *number_result)); -int utf8_to_utf16 __ARGS((char_u *instr, int inlen, short_u *outstr, int *unconvlenp)); -int utf16_to_utf8 __ARGS((short_u *instr, int inlen, char_u *outstr)); -void MultiByteToWideChar_alloc __ARGS((UINT cp, DWORD flags, LPCSTR in, int inlen, LPWSTR *out, int *outlen)); -void WideCharToMultiByte_alloc __ARGS((UINT cp, DWORD flags, LPCWSTR in, int inlen, LPSTR *out, int *outlen, LPCSTR def, LPBOOL useddef)); -int clip_mch_own_selection __ARGS((VimClipboard *cbd)); -void clip_mch_lose_selection __ARGS((VimClipboard *cbd)); -void clip_mch_request_selection __ARGS((VimClipboard *cbd)); -void clip_mch_set_selection __ARGS((VimClipboard *cbd)); -short_u *enc_to_utf16 __ARGS((char_u *str, int *lenp)); -char_u *utf16_to_enc __ARGS((short_u *str, int *lenp)); -void acp_to_enc __ARGS((char_u *str, int str_size, char_u **out, int *outlen)); void DumpPutS __ARGS((const char *psz)); int mch_get_winpos __ARGS((int *x, int *y)); void mch_set_winpos __ARGS((int x, int y)); diff --git a/src/proto/winclip.pro b/src/proto/winclip.pro new file mode 100644 --- /dev/null +++ b/src/proto/winclip.pro @@ -0,0 +1,14 @@ +/* winclip.c */ +int utf8_to_utf16 __ARGS((char_u *instr, int inlen, short_u *outstr, int *unconvlenp)); +int utf16_to_utf8 __ARGS((short_u *instr, int inlen, char_u *outstr)); +void MultiByteToWideChar_alloc __ARGS((UINT cp, DWORD flags, LPCSTR in, int inlen, LPWSTR *out, int *outlen)); +void WideCharToMultiByte_alloc __ARGS((UINT cp, DWORD flags, LPCWSTR in, int inlen, LPSTR *out, int *outlen, LPCSTR def, LPBOOL useddef)); +void win_clip_init __ARGS((void)); +int clip_mch_own_selection __ARGS((VimClipboard *cbd)); +void clip_mch_lose_selection __ARGS((VimClipboard *cbd)); +void clip_mch_request_selection __ARGS((VimClipboard *cbd)); +void clip_mch_set_selection __ARGS((VimClipboard *cbd)); +short_u *enc_to_utf16 __ARGS((char_u *str, int *lenp)); +char_u *utf16_to_enc __ARGS((short_u *str, int *lenp)); +void acp_to_enc __ARGS((char_u *str, int str_size, char_u **out, int *outlen)); +/* vim: set ft=c : */ diff --git a/src/term.c b/src/term.c --- a/src/term.c +++ b/src/term.c @@ -1853,7 +1853,9 @@ set_termname(term) # ifdef FEAT_GUI if (!gui.in_use) # endif +# ifndef FEAT_CYGWIN_WIN32_CLIPBOARD clip_init(FALSE); +# endif # endif if (use_xterm_like_mouse(term)) { diff --git a/src/version.c b/src/version.c --- a/src/version.c +++ b/src/version.c @@ -729,6 +729,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ /**/ + 836, +/**/ 835, /**/ 834, diff --git a/src/vim.h b/src/vim.h --- a/src/vim.h +++ b/src/vim.h @@ -1927,7 +1927,7 @@ typedef struct VimClipboard GdkAtom gtk_sel_atom; /* PRIMARY/CLIPBOARD selection ID */ # endif -# ifdef MSWIN +# if defined(MSWIN) || defined(FEAT_CYGWIN_WIN32_CLIPBOARD) int_u format; /* Vim's own special clipboard format */ int_u format_raw; /* Vim's raw text clipboard format */ # endif diff --git a/src/winclip.c b/src/winclip.c new file mode 100644 --- /dev/null +++ b/src/winclip.c @@ -0,0 +1,798 @@ +/* vi:set ts=8 sts=4 sw=4: + * + * VIM - Vi IMproved by Bram Moolenaar + * + * Do ":help uganda" in Vim to read copying and usage conditions. + * Do ":help credits" in Vim to see a list of people who contributed. + * See README.txt for an overview of the Vim source code. + */ + +/* + * winclip.c + * + * Routines common to both Win16 and Win32 for clipboard handling. + * Also used by Cygwin, using os_unix.c. + */ + +#ifdef WIN16 +# ifdef __BORLANDC__ +# pragma warn -par +# pragma warn -ucp +# pragma warn -use +# pragma warn -aus +# endif +#endif + +#include "vimio.h" +#include "vim.h" + +/* + * Compile only the clipboard handling features when compiling for cygwin + * posix environment. + */ +#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD +# define WIN3264 +# define WIN32_LEAN_AND_MEAN +# include +# include "winclip.pro" +#endif + +/* + * When generating prototypes for Win32 on Unix, these lines make the syntax + * errors disappear. They do not need to be correct. + */ +#ifdef PROTO +#define WINAPI +#define WINBASEAPI +typedef int DWORD; +typedef int LPBOOL; +typedef int LPCSTR; +typedef int LPCWSTR; +typedef int LPSTR; +typedef int LPWSTR; +typedef int UINT; +#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. + */ + + void +win_clip_init(void) +{ + clip_init(TRUE); + + /* + * Vim's own clipboard format recognises whether the text is char, line, + * or rectangular block. Only useful for copying between two Vims. + * "VimClipboard" was used for previous versions, using the first + * character to specify MCHAR, MLINE or MBLOCK. + */ + clip_star.format = RegisterClipboardFormat("VimClipboard2"); + clip_star.format_raw = RegisterClipboardFormat("VimRawBytes"); +} + +/* 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*). + * + */ + 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 into . */ + 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