[PATCH v2 1/2] Cygwin: pty: Revise convert_mb_str() function.

Corinna Vinschen corinna-cygwin@cygwin.com
Wed Sep 9 14:12:36 GMT 2020


On Sep  9 22:40, Takashi Yano via Cygwin-patches wrote:
> - Use tmp_pathbuf instead of HeapAlloc()/HeapFree().
> - Remove mb_str_free() function.
> - Consider the case where the multibyte string stops in the middle
>   of a multibyte char.
> ---
>  winsup/cygwin/fhandler_tty.cc | 118 ++++++++++++++++++++++------------
>  1 file changed, 77 insertions(+), 41 deletions(-)
> 
> diff --git a/winsup/cygwin/fhandler_tty.cc b/winsup/cygwin/fhandler_tty.cc
> index 6de591d9b..c4b7fc61d 100644
> --- a/winsup/cygwin/fhandler_tty.cc
> +++ b/winsup/cygwin/fhandler_tty.cc
> @@ -26,6 +26,7 @@ details. */
>  #include <asm/socket.h>
>  #include "cygwait.h"
>  #include "registry.h"
> +#include "tls_pbuf.h"
>  
>  #ifndef PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE
>  #define PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE 0x00020016
> @@ -116,40 +117,72 @@ CreateProcessW_Hooked
>    return CreateProcessW_Orig (n, c, pa, ta, inh, f, e, d, si, pi);
>  }
>  
> -static char *
> -convert_mb_str (UINT cp_to, size_t *len_to,
> -		UINT cp_from, const char *ptr_from, size_t len_from)
> +static void
> +convert_mb_str (UINT cp_to, char *ptr_to, size_t *len_to,
> +		UINT cp_from, const char *ptr_from, size_t len_from,
> +		mbstate_t *stat)

Heh, it's funny to use mbstate_t together with Windows functions :)
However, the var name `stat' makes me itch.  It looks too close to
struct stat and function stat.  What about "mbp" or something along
these lines?

>  {
> -  char *buf;
>    size_t nlen;
> +  tmp_pathbuf tp;
>    if (cp_to != cp_from)
>      {
> -      size_t wlen =
> -	MultiByteToWideChar (cp_from, 0, ptr_from, len_from, NULL, 0);
> -      wchar_t *wbuf = (wchar_t *)
> -	HeapAlloc (GetProcessHeap (), 0, wlen * sizeof (wchar_t));
> -      wlen =
> -	MultiByteToWideChar (cp_from, 0, ptr_from, len_from, wbuf, wlen);
> -      nlen = WideCharToMultiByte (cp_to, 0, wbuf, wlen, NULL, 0, NULL, NULL);
> -      buf = (char *) HeapAlloc (GetProcessHeap (), 0, nlen);
> -      nlen = WideCharToMultiByte (cp_to, 0, wbuf, wlen, buf, nlen, NULL, NULL);
> -      HeapFree (GetProcessHeap (), 0, wbuf);
> +      wchar_t *wbuf = tp.w_get ();
> +      int wlen = 0;
> +      if (cp_from == 65000) /* UTF-7 */

CP_UTF7?

> +	/* MB_ERR_INVALID_CHARS does not work properly for UTF-7.
> +	   Therefore, just convert string without checking */
> +	wlen = MultiByteToWideChar (cp_from, 0, ptr_from, len_from,
> +				    wbuf, NT_MAX_PATH);
> +      else
> +	{
> +	  char *tmpbuf = tp.c_get ();
> +	  memcpy (tmpbuf, stat->__value.__wchb, stat->__count);
> +	  if (stat->__count + len_from > NT_MAX_PATH)
> +	    len_from = NT_MAX_PATH - stat->__count;
> +	  memcpy (tmpbuf + stat->__count, ptr_from, len_from);
> +	  int total_len = stat->__count + len_from;
> +	  stat->__count = 0;
> +	  int mblen = 0;
> +	  for (const char *p = tmpbuf; p < tmpbuf + total_len; p += mblen)
> +	    /* Max bytes in multibyte char is 4. */
> +	    for (mblen = 1; mblen <= 4; mblen ++)
> +	      {
> +		/* Try conversion */
> +		int l = MultiByteToWideChar (cp_from, MB_ERR_INVALID_CHARS,
> +					     p, mblen,
> +					     wbuf + wlen, NT_MAX_PATH - wlen);
> +		if (l)
> +		  { /* Conversion Success */
> +		    wlen += l;
> +		    break;
> +		  }
> +		else if (mblen == 4)
> +		  { /* Conversion Fail */
> +		    l = MultiByteToWideChar (cp_from, 0, p, 1,
> +					     wbuf + wlen, NT_MAX_PATH - wlen);
> +		    wlen += l;
> +		    mblen = 1;
> +		    break;
> +		  }
> +		else if (p + mblen == tmpbuf + total_len)
> +		  { /* Multibyte char incomplete */
> +		    memcpy (stat->__value.__wchb, p, mblen);
> +		    stat->__count = mblen;
> +		    break;
> +		  }
> +		/* Retry conversion with extended length */
> +	      }
> +	}
> +      nlen = WideCharToMultiByte (cp_to, 0, wbuf, wlen,
> +				  ptr_to, *len_to, NULL, NULL);
>      }
>    else
>      {
>        /* Just copy */
> -      buf = (char *) HeapAlloc (GetProcessHeap (), 0, len_from);
> -      memcpy (buf, ptr_from, len_from);
> -      nlen = len_from;
> +      nlen = min (*len_to, len_from);
> +      memcpy (ptr_to, ptr_from, nlen);

if the *caller* checks for cp_to != cp_from, this memcpy could go
away and the caller could just use the already existing buffer.

Other than that, LGTM.


Thanks,
Corinna


More information about the Cygwin-patches mailing list