4 * MinGW.org replacement for the wcrtomb() function; supports use of this
5 * function on legacy Windows versions, for which it is not available in the
6 * C runtime DLL, and replaces the Microsoft implementation, in those cases
7 * where one is available.
12 * Written by Keith Marshall <keith@users.osdn.me>
13 * Copyright (C) 2019, 2020, MinGW.org Project
16 * Permission is hereby granted, free of charge, to any person obtaining a
17 * copy of this software and associated documentation files (the "Software"),
18 * to deal in the Software without restriction, including without limitation
19 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
20 * and/or sell copies of the Software, and to permit persons to whom the
21 * Software is furnished to do so, subject to the following conditions:
23 * The above copyright notice, this permission notice, and the following
24 * disclaimer shall be included in all copies or substantial portions of
27 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
28 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
29 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
30 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
31 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
32 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER
33 * DEALINGS IN THE SOFTWARE.
38 static __mb_inline__ size_t __wcrtomb_internal
39 ( char *restrict mb, wchar_t wc, mbstate_t *ps )
41 /* Internal implementation of the wcrtomb() function; this is
42 * expanded inline, within the public implementation.
44 if( *ps != (mbstate_t)(0) )
46 /* Microsoft's MBCS implementation does not use shift states;
47 * however, it is possible that an immediately preceding call
48 * may have stopped with a dangling high surrogate, and thus
49 * a restart to complete this, by adding a low surrogate, and
50 * converting the pair, may be appropriate.
52 if( IS_HIGH_SURROGATE( *ps ) && IS_LOW_SURROGATE( wc ) )
54 /* Reassemble the surrogate pair, in a local buffer, and
55 * return its conversion, having reset the restart state.
57 wchar_t buf[2] = { (wchar_t)(*ps), wc }; *ps = (mbstate_t)(0);
58 return __mingw_wctomb_convert( mb, __mingw_wctomb_cur_max(), buf, 2 );
61 { /* We expected a low surrogate, but didn't get one; reset
62 * the restart state, and abort this conversion.
64 *ps = (mbstate_t)(0); return errout( EILSEQ, (size_t)(-1) );
67 /* When mb is a NULL pointer, ISO-C99 decrees that the call shall
68 * be interpreted as the equivalent of:
70 * wcrtomb( internal_buffer, L'\0', ps );
72 * with the encoding of the NUL wchar, preceded by any sequence
73 * of bytes needed to restore ps to the initial shift state, being
74 * stored in the internal buffer, (and thus, inaccessible to the
75 * caller). Since Microsoft's MBCS encodings do not use shift
76 * states, and the encoding for NUL is always a single NUL byte,
77 * this becomes the equivalent of returning (size_t)(1).
79 if( mb == NULL ) return (size_t)(1);
81 /* When mb is not a NULL pointer, then we are obliged to assume
82 * that it points to a buffer of at least MB_CUR_MAX bytes, and
83 * we may proceed with a normal conversion, (except that, when
84 * wc lies in the range reserved for surrogates, we must handle
85 * it as a special case.
87 if( IS_HIGH_SURROGATE( wc ) )
88 { /* A high surrogate is permitted, but it cannot be converted
89 * at this time; instead, we simply record that it is present,
90 * (subverting ps for this purpose), and move on, without any
91 * conversion being performed, and thus storing no converted
92 * bytes, in the expection that the next wc passed will be a
93 * low surrogate, thus allowing completion of the conversion.
95 *ps = (mbstate_t)(wc); return (size_t)(0);
97 if( IS_LOW_SURROGATE( wc ) )
98 /* A low surrogate, detected here, is an orphan (not paired
99 * with a high surrogate from an immediately preceding call);
100 * this is not permitted, so report it as invalid.
102 return errout( EILSEQ, (size_t)(-1) );
104 /* If we get this far, we may proceed with conversion; we return
105 * the byte count, and effect of encoding the single wchar which
106 * was passed by value in wc.
108 return __mingw_wctomb_convert( mb, __mingw_wctomb_cur_max(), &wc, 1 );
111 size_t wcrtomb( char *restrict mb, wchar_t wc, mbstate_t *restrict ps )
113 /* Implementation of ISO-C99 wcrtomb() function, in libmingwex.a;
114 * after storing the effective codeset properties, this returns the
115 * result from expansion of the preceding inline implementation.
117 (void)(__mingw_wctomb_cur_max_init( __mingw_wctomb_codeset_init() ));
118 return __wcrtomb_internal( mb, wc, __mbrtowc_state( ps ) );
121 /* FIXME: these aliases are provided for link-compatibitity with
122 * libraries compiled against mingwrt-5.3.x; they may be removed
123 * from future versions of mingwrt.
125 size_t __msvcrt_wcrtomb( char *restrict, wchar_t, mbstate_t *restrict )
126 __attribute__((__weak__,__alias__("wcrtomb")));
128 size_t __mingw_wcrtomb( char *restrict, wchar_t, mbstate_t *restrict )
129 __attribute__((__weak__,__alias__("wcrtomb")));
131 /* $RCSfile$: end of file */