diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index 7ae793f3b..998be8dbd 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,15 @@ +2012-07-02 Corinna Vinschen + + * fhandler.h (class fhandler_dev_clipboard): Remove member eof. + * fhandler_clipboard.cc: Throughout remove handling of eof member. + (fhandler_dev_clipboard::write): Handle EOF condition immediately, + rather than pushing it erroneously to the next read call. Rearrange + code. Fix bug in CF_UNICODETEXT case which potentially dropped single + bytes at the end of the buffer. Add comment. + * strfuncs.cc (sys_cp_wcstombs): Allow returning non-NUL-terminated + buffer if dst != NULL and len == (size_t) -1. Extend leading comment + to explain what's returned in more detail. + 2012-07-02 Christopher Faylor * fhandler_virtual.cc (fhandler_virtual::opendir): Eliminate duplicate diff --git a/winsup/cygwin/fhandler.h b/winsup/cygwin/fhandler.h index 72f8d8429..9f30f5cc0 100644 --- a/winsup/cygwin/fhandler.h +++ b/winsup/cygwin/fhandler.h @@ -1721,7 +1721,6 @@ class fhandler_dev_clipboard: public fhandler_base _off64_t pos; void *membuffer; size_t msize; - bool eof; public: fhandler_dev_clipboard (); int is_windows () { return 1; } diff --git a/winsup/cygwin/fhandler_clipboard.cc b/winsup/cygwin/fhandler_clipboard.cc index 203af58bb..86f126c24 100644 --- a/winsup/cygwin/fhandler_clipboard.cc +++ b/winsup/cygwin/fhandler_clipboard.cc @@ -41,8 +41,7 @@ typedef struct } cygcb_t; fhandler_dev_clipboard::fhandler_dev_clipboard () - : fhandler_base (), pos (0), membuffer (NULL), msize (0), - eof (true) + : fhandler_base (), pos (0), membuffer (NULL), msize (0) { /* FIXME: check for errors and loop until we can open the clipboard */ OpenClipboard (NULL); @@ -69,7 +68,6 @@ int fhandler_dev_clipboard::open (int flags, mode_t) { set_flags (flags | O_TEXT); - eof = false; pos = 0; if (membuffer) free (membuffer); @@ -158,38 +156,28 @@ set_clipboard (const void *buf, size_t len) ssize_t __stdcall fhandler_dev_clipboard::write (const void *buf, size_t len) { - if (!eof) + /* write to our membuffer */ + size_t cursize = msize; + void *tempbuffer = realloc (membuffer, cursize + len); + if (!tempbuffer) { - /* write to our membuffer */ - size_t cursize = msize; - void *tempbuffer = realloc (membuffer, cursize + len); - if (!tempbuffer) - { - debug_printf ("Couldn't realloc() clipboard buffer for write"); - return -1; - } - membuffer = tempbuffer; - msize = cursize + len; - memcpy ((unsigned char *) membuffer + cursize, buf, len); - - /* now pass to windows */ - if (set_clipboard (membuffer, msize)) - { - /* FIXME: membuffer is now out of sync with pos, but msize - is used above */ - return -1; - } - - pos = msize; - - eof = false; - return len; + debug_printf ("Couldn't realloc() clipboard buffer for write"); + return -1; } - else + membuffer = tempbuffer; + msize = cursize + len; + memcpy ((unsigned char *) membuffer + cursize, buf, len); + + /* now pass to windows */ + if (set_clipboard (membuffer, msize)) { - /* FIXME: return 0 bytes written, file not open */ - return 0; + /* FIXME: membuffer is now out of sync with pos, but msize + is used above */ + return -1; } + + pos = msize; + return len; } int __stdcall @@ -230,66 +218,65 @@ void __stdcall fhandler_dev_clipboard::read (void *ptr, size_t& len) { HGLOBAL hglb; - size_t ret; + size_t ret = 0; UINT formatlist[2]; int format; - size_t plen = len; + LPVOID cb_data; - len = 0; - if (eof) - return; if (!OpenClipboard (NULL)) - return; - formatlist[0] = cygnativeformat; - formatlist[1] = CF_UNICODETEXT; - if ((format = GetPriorityClipboardFormat (formatlist, 2)) <= 0) { - CloseClipboard (); + len = 0; return; } - if (!(hglb = GetClipboardData (format))) + formatlist[0] = cygnativeformat; + formatlist[1] = CF_UNICODETEXT; + if ((format = GetPriorityClipboardFormat (formatlist, 2)) <= 0 + || !(hglb = GetClipboardData (format)) + || !(cb_data = GlobalLock (hglb))) { CloseClipboard (); + len = 0; return; } if (format == cygnativeformat) { - cygcb_t *clipbuf; + cygcb_t *clipbuf = (cygcb_t *) cb_data; - if (!(clipbuf = (cygcb_t *) GlobalLock (hglb))) - { - CloseClipboard (); - return; + if (pos < clipbuf->len) + { + ret = ((len > (clipbuf->len - pos)) ? (clipbuf->len - pos) : len); + memcpy (ptr, clipbuf->data + pos , ret); + pos += ret; } - ret = ((plen > (clipbuf->len - pos)) ? (clipbuf->len - pos) : plen); - memcpy (ptr, clipbuf->data + pos , ret); - pos += ret; - if (pos + plen - ret >= clipbuf->len) - eof = true; } else { - int wret; - PWCHAR buf; + wchar_t *buf = (wchar_t *) cb_data; - if (!(buf = (PWCHAR) GlobalLock (hglb))) - { - CloseClipboard (); - return; - } size_t glen = GlobalSize (hglb) / sizeof (WCHAR) - 1; - /* This loop is necessary because the number of bytes returned by - sys_wcstombs does not indicate the number of wide chars used for - it, so we could potentially drop wide chars. */ - if (glen - pos > plen) - glen = pos + plen; - while ((wret = sys_wcstombs (NULL, 0, buf + pos, glen - pos)) != -1 - && (size_t) wret > plen) - --glen; - ret = sys_wcstombs ((char *) ptr, plen, buf + pos, glen - pos); - pos += ret; - if (pos + plen - ret >= wcslen (buf)) - eof = true; + if (pos < glen) + { + /* Comparing apples and oranges here, but the below loop could become + extremly slow otherwise. We rather return a few bytes less than + possible instead of being even more slow than usual... */ + if (glen > pos + len) + glen = pos + len; + /* This loop is necessary because the number of bytes returned by + sys_wcstombs does not indicate the number of wide chars used for + it, so we could potentially drop wide chars. */ + while ((ret = sys_wcstombs (NULL, 0, buf + pos, glen - pos)) + != (size_t) -1 + && ret > len) + --glen; + if (ret == (size_t) -1) + ret = 0; + else + { + ret = sys_wcstombs ((char *) ptr, (size_t) -1, + buf + pos, glen - pos); + pos = glen; + } + } } GlobalUnlock (hglb); CloseClipboard (); @@ -316,7 +303,6 @@ fhandler_dev_clipboard::close () { if (!have_execed) { - eof = true; pos = 0; if (membuffer) { @@ -333,7 +319,6 @@ fhandler_dev_clipboard::fixup_after_exec () { if (!close_on_exec ()) { - eof = false; pos = msize = 0; membuffer = NULL; } diff --git a/winsup/cygwin/strfuncs.cc b/winsup/cygwin/strfuncs.cc index 467f54e87..22ba4d619 100644 --- a/winsup/cygwin/strfuncs.cc +++ b/winsup/cygwin/strfuncs.cc @@ -393,9 +393,23 @@ __big5_mbtowc (struct _reent *r, wchar_t *pwc, const char *s, size_t n, sequence in by treating it as an UTF-8 char. If that fails, the ASCII CAN was probably standalone and it gets just copied over as ASCII CAN. - - The functions always create 0-terminated results, no matter what. - If the result is truncated due to buffer size, it's a bug in Cygwin - and the buffer in the calling function should be raised. */ + - Three cases have to be distinguished for the return value: + + - dst == NULL; len is ignored, the return value is the number of bytes + required for the string without the trailing NUL, just like the return + value of the wcstombs function. + + - dst != NULL, len == (size_t) -1; the return value is the size in bytes + of the destination string without the trailing NUL. If the incoming + wide char string was not NUL-terminated, the target string won't be + NUL-terminated either. + + - dst != NULL; len != (size_t) -1; the return value is the size in bytes + of the destination string without the trailing NUL. The target string + will be NUL-terminated, no matter what. If the result is truncated due + to buffer size, it's a bug in Cygwin and the buffer in the calling + function should be raised. +*/ size_t __stdcall sys_cp_wcstombs (wctomb_p f_wctomb, const char *charset, char *dst, size_t len, const wchar_t *src, size_t nwc) @@ -473,7 +487,7 @@ sys_cp_wcstombs (wctomb_p f_wctomb, const char *charset, char *dst, size_t len, else break; } - if (n && dst) + if (n && dst && len != (size_t) -1) { n = (n < len) ? n : len - 1; dst[n] = '\0';