%PAGEREF%(MinGW)

NAME
wcrtomb - convert a wide character to a multibyte sequence

SYNOPSIS
#include <wchar.h>

size_t wcrtomb( char *s, wchar_t wc, mbstate_t *ps );

DESCRIPTION
The wcrtomb() function determines the number of bytes which are required, starting from the conversion state represented by the mbstate_t object at *ps, to accommodate the multibyte character sequence, in the codeset associated with the LC_CTYPE category of the active process locale, which represents the completed conversion of the wide character specified by wc.

In the special case, when s is a NULL pointer, the wc argument is ignored, and the call is evaluated as if it had been invoked as

        wcrtomb( buf, L'\0', ps )

returning the effect of conversion of the NUL wide character, as a completion of any intermediate conversion state specified in *ps, but without storing the converted multibyte sequence; (in this special case, the ISO-C99 standard specifies that buf should be an internal buffer, but since such a buffer becomes effectively inaccessible, storage of any converted multibyte sequence is unnecessary).

Conversely, in the normal case, when s is not a NULL pointer, the wcrtomb() function converts the wide character, represented by wc, to the corresponding multibyte character sequence, which is stored in the byte array starting at *s, and the function return value is set to the number of bytes stored.

RETURN VALUE
When conversion is successful, regardless of whether the resultant multibyte sequence is stored, or not, the wcrtomb() function returns the number of bytes which are, or which would be, stored at *s.

If the result of conversion represents a completed multibyte sequence, the conversion state, represented by *ps, is updated to represent the initial state. Conversely, if the result of conversion is equivalent to the conversion of a high surrogate, nothing is stored, the return value is set to zero, and the conversion state is updated to represent a pending surrogate pair completion.

ERROR CONDITIONS
If the wide character, passed as wc, either cannot be converted to a valid multibyte sequence, or does not complete a pending surrogate pair which can be represented as a valid multibyte sequence, in the codeset of the active LC_CTYPE locale category, errno is set to EILSEQ, the wcrtomb() function returns (size_t)(-1), and the conversion state is unspecified.

STANDARDS CONFORMANCE
Except in respect of its extended provision for handling of surrogate pairs, and to the extent that it may be affected by limitations of the underlying MS-Windows API, the libmingwex implementation of wcrtomb() conforms generally to ISO-C99, POSIX.1-2001, and POSIX.1-2008.

CAVEATS AND BUGS
Due to a documented limitation of Microsoft's setlocale() function implementation, it is not possible to directly select an active locale, in which the codeset is represented by any multibyte character sequence with an effective MB_CUR_MAX of more than two bytes. Prior to mingwrt-5.3, this limitation precludes the use of wcrtomb() to interpret any codeset with MB_CUR_MAX greater than two bytes, (such as UTF-8). From mingwrt-5.3 onward, the MinGW.org implementation of wcrtomb() mitigates this limitation by assignment of the codeset from the LC_CTYPE environment variable, provided the system default has been previously activated for the LC_CTYPE locale category; e.g. execution of:

        #define _ISOC99_SOURCE
        #include <stdio.h>
        #include <stdlib.h>
        #include <locale.h>
        #include <limits.h>
        #include <wchar.h>
        void print_conv( const wchar_t * );
        int main()
        {
          setlocale( LC_CTYPE, "" );
          putenv( "LC_CTYPE=en_GB.65001" );
          print_conv( L"\u6c34\U0001d10b" );
          return 0;
        }
        void print_conv( const wchar_t *wcs )
        {
          wchar_t wch;
          while( (wch = *wcs++) != L'\0' )
          {
            char mbs[MB_LEN_MAX];
            mbstate_t ps = (mbstate_t)(0);
            size_t n = wcrtomb( mbs, wch, &ps );
            if( (int)(n) > 0 )
            {
              unsigned char *p = (unsigned char *)(mbs);
              printf( "Single wide character: 0x%04X --> %u byte%s",
        	  wch, n, (n == 1) ? ":  " : "s: "
        	);
              while( n > 0 )
        	printf( "0x%02X%c", *p++, (--n == 0) ? '\n' : ':' );
            }
            else if( n == (size_t)(-1) ) perror( "wcrtomb" );
          }
        }

will successfully convert the L"\u6c34" wide character to its UTF-8 equivalent, resulting in the output:

        Single wide character: 0x6C34 --> 3 bytes: 0xE6:0xB0:0xB4

However, when it then progresses to the L"\U0001d10b" wide character, (which should be represented by a valid UTF-16LE surrogate pair), it fails with the diagnostic:

        wcrtomb: Invalid or incomplete multibyte or wide character

This (possibly unexpected) failure is an unfortunate consequence of Microsoft's choice of UTF-16LE as the underlying representation of the wchar_t data type; this choice makes it impossible for any MS-Windows implementation of wcrtomb() to be fully ISO-C99 compliant. To mitigate this non-compliance, the MinGW implementation of wcrtomb() incorporates the following non-standard capabilities:

    •   When the mbstate_t argument refers to the initial conversion state, and the wchar_t argument represents a high surrogate, then nothing is stored in the conversion buffer, the mbstate_t reference is updated to indicate pending completion of the surrogate, and the function returns an effective conversion count of zero bytes.

    •   When the mbstate_t argument refers to a pending completion of a surrogate pair, and the wchar_t argument represents a low surrogate, then the deferred high surrogate is combined with the low surrogate argument, and the two are converted as a pair; the resultant conversion is stored in the conversion buffer, the mbstate_t reference is reset to the initial conversion state, and the function returns the number of bytes which were stored in the conversion buffer.

These capabilities of MinGW's wcrtomb() are certainly non-standard; nonetheless, they are required to circumvent non-conformity, which is imposed by an unfortunate Microsoft design choice, and it is incumbent upon the caller of wcrtomb(), on the MS-Windows platform, to make use of them. The preceding example clearly illustrates how strictly ISO-C99 conforming usage will yield incorrect behaviour; the following illustrates how that example may be adapted, by incorporation of the above non-standard features, to achieve correct behaviour:

        #define _ISOC99_SOURCE
        #include <stdio.h>
        #include <stdlib.h>
        #include <locale.h>
        #include <limits.h>
        #include <winnls.h>
        #include <wchar.h>
        void print_conv( const wchar_t * );
        int main()
        {
          setlocale( LC_CTYPE, "" );
          putenv( "LC_CTYPE=en_GB.65001" );
          print_conv( L"\u6c34\U0001d10b" );
          return 0;
        }
        #define DESC(FMT)  FMT "0x%1$04X --> %2$u byte%3$s"
        void print_conv( const wchar_t *wcs )
        {
          while( *wcs != L'\0' )
          {
            wchar_t wch = *wcs;
            char mbs[MB_LEN_MAX];
            mbstate_t ps = (mbstate_t)(0);
            const char *fmt = DESC( "Single wide character: " );
            size_t n = wcrtomb( mbs, wch, &ps );
            if( (n == (size_t)(0)) && IS_HIGH_SURROGATE( wch ) )
            {
              if( (int)(n = wcrtomb( mbs, wcs[1], &ps )) > 0 )
              {
                fmt = DESC( "Surrogate pair: 0x%1$04X:" );
                wcs++;
              }
            }
            if( (int)(n) > 0 )
            {
              unsigned char *p = (unsigned char *)(mbs);
              printf( fmt, wch, n, (n == 1) ? ":  " : "s: ", *wcs );
              while( n > 0 )
                printf( "0x%02X%c", *p++, (--n == 0) ? '\n' : ':' );
            }
            else if( n == (size_t)(-1) ) perror( "wcrtomb" );
            if( *wcs != L'\0' ) ++wcs;
          }
        }

It may be observed that, on execution of this modified version of the example, both the L"\u6c34", and the L"\U0001d10b" code points are now correctly evaluated, producing the expected output:

        Single wide character: 0x6C34 --> 3 bytes: 0xE6:0xB0:0xB4
        Surrogate pair: 0xD834:0xD834 --> 4 bytes: 0xF0:0x9D:0x84:0x8B

SEE ALSO
mbsinit(3), and wcsrtombs(3)

AUTHOR
This manpage was written by Keith Marshall, <keith@users.osdn.me>, to document the wcrtomb() function as it has been implemented for the MinGW.org Project. It may be copied, modified and redistributed, without restriction of copyright, provided this acknowledgement of contribution by the original author remains in place.