%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 );

    Feature Test Macro Requirements for libmingwex:

__MSVCRT_VERSION__: since mingwrt-5.3, if this feature test macro is defined, with a value of at least 0x0800, (corresponding to the symbolic constant, __MSCVR80_DLL, and thus declaring intent to link with MSVCR80.DLL, or any later version of Microsoft's non-free runtime library, instead of with MSVCRT.DLL), calls to wcrtomb() will be directed to the implementation thereof, within Microsoft's runtime DLL.

_ISOC99_SOURCE, _ISOC11_SOURCE: since mingwrt-5.3.1, when linking with MSVCRT.DLL, or when __MSVCRT_VERSION__ is either undefined, or is defined with any value which is less than 0x0800, (thus denying intent to link with MSVCR80.DLL, or any later non-free version of Microsoft's runtime library), explicitly defining either of these feature test macros will cause any call to wcrtomb() to be directed to the libmingwex implementation; if neither macro is defined, calls to wcrtomb() will be directed to Microsoft's runtime implementation, if it is available, otherwise falling back to the libmingwex implementation.

Prior to mingwrt-5.3, none of the above feature test macros have any effect on wcrtomb(); all calls will be directed to the libmingwex implementation.

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; (prior to mingwrt-5.3, and in those cases where calls may be delegated to a Microsoft runtime DLL implementation, this level of conformity may not be achieved).

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.