4 * MinGW.OSDN implementation of the wcsrtombs() function; supports use of
5 * this function on any legacy Windows version, for which Microsoft do not
6 * provide it, and replaces the Microsoft implementation, when they do.
11 * Written by Keith Marshall <keith@users.osdn.me>
12 * Copyright (C) 2019, 2020, 2022, MinGW.OSDN Project
15 * Permission is hereby granted, free of charge, to any person obtaining a
16 * copy of this software and associated documentation files (the "Software"),
17 * to deal in the Software without restriction, including without limitation
18 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
19 * and/or sell copies of the Software, and to permit persons to whom the
20 * Software is furnished to do so, subject to the following conditions:
22 * The above copyright notice, this permission notice, and the following
23 * disclaimer shall be included in all copies or substantial portions of
26 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
27 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
29 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
31 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER
32 * DEALINGS IN THE SOFTWARE.
37 static __mb_inline__ size_t __mingw_wcsrtombs_internal
38 ( char *restrict mbs, const wchar_t **restrict wcs, size_t len,
39 mbstate_t *restrict ps
41 { /* Internal implementation of the wcsrtombs() function; this will be
42 * expanded inline, within the body of the public implementation.
44 * Initially, save the current errno state, so that we may restore
45 * it on return, clear it to zero for internal checking, and compute
46 * the size of buffer required to accommodate the conversion.
48 int errno_reset = save_error_status_and_clear( errno, 0 );
49 union { mbstate_t ps; wchar_t wc[2]; } resume = { (mbstate_t)(0) };
50 size_t count = (size_t)(0), wanted = (size_t)(0);
52 /* This wcsrtombs() implementation will not use any mbstate...
55 { /* ...unless it is provided by the caller, in which case we will,
56 * ultimately, reset it to initial state, after processing it...
60 if( IS_SURROGATE_PAIR( resume.wc[0], **wcs ) )
61 { /* ...subject to the expectation that it represents deferred
62 * completion of a surrogate pair.
64 resume.wc[1] = *(*wcs)++;
65 count = __mingw_wctomb_convert( NULL, 0, resume.wc, 2 );
69 /* The total buffer space wanted is the aggregate of any deferred
70 * surrogate pair completion, plus the contribution from conversion
71 * of the remainder of the wide character string.
73 wanted = count + __mingw_wctomb_convert( NULL, 0, *wcs, -1 );
76 /* There is no buffer designated to store the encoded multibyte
77 * character sequence; we are only interested in the size of the
78 * buffer which would otherwise be required, and we've already
79 * determined that, so simply return it.
81 return (errno == 0) ? errout( errno_reset, wanted - 1 ) : wanted;
83 if( (errno == 0) && (len >= wanted) )
84 { /* There is an encoding buffer designated, its size is sufficient
85 * to accommodate the encoding of the entire NUL terminated input
86 * sequence, and there was no incipient encoding error during the
87 * initial minimum buffer size determination; encode the entire
88 * input sequence for return, and clean up the input state.
90 if( count != (size_t)(0) )
91 mbs += __mingw_wctomb_convert( mbs, len, resume.wc, 2 );
92 count += __mingw_wctomb_convert( mbs, len - count, *wcs, -1 ) - 1;
97 { /* There is an encoding buffer designated, but either it is too
98 * small, or a incipient encoding error has been detected; rescan
99 * the input sequence, encoding one code point at a time, until we
100 * either exhaust the encoding buffer space, or we encounter the
101 * encoding error previously identified.
105 /* Initially, if there's a pending surrogate completion, and there
106 * is insufficient buffer space to accommodate its conversion, then
107 * we must squash all conversion...
109 if( count > len ) count = len = 0;
110 else if( count != 0 )
111 { /* ...otherwise, we store the completed surrogate conversion, at
112 * the start of the buffer, adjusting the buffer pointer, and its
113 * residual length counter, to suit.
115 mbs += __mingw_wctomb_convert( mbs, len, resume.wc, 2 );
118 while( (len >= __mingw_wctomb_convert( NULL, 0, *wcs, 1 )) && (errno == 0) )
120 /* There is still sufficient space to store the encoding of one
121 * more input code point, and we haven't yet fallen foul of any
122 * incipient encoding error; store this encoding, and adjust to
123 * prepare for the next.
125 size_t step = __mingw_wctomb_convert( mbs, len, (*wcs)++, 1 );
126 count += step; len -= step; mbs += step;
129 /* Check that we didn't fall foul of any incipient encoding error;
130 * if we did, then we must bail out.
132 if( errno != 0 ) return (size_t)(-1);
134 /* We have now successfully encoded as much of the input sequence
135 * as possible, without encountering any encoding error; restore
136 * the saved errno state, and return the encoded byte count.
138 return errout( errno_reset, count );
141 size_t wcsrtombs( char *mbs, const wchar_t **wcs, size_t len, mbstate_t *ps )
143 /* Implementation of ISO-C99 wcsrtombs() function, in libmingwex.a;
144 * before proceeding, we must ensure that the wcs argument specifies
145 * an indirect reference to a non-NULL wchar_t array.
147 if( (wcs == NULL) || (*wcs == NULL) ) return errout( EINVAL, (size_t)(-1) );
149 /* With a valid wcs reference, store the effective codeset, and
150 * hand the conversion off to the inline expansion of the preceding
153 (void)(__mingw_wctomb_codeset_init() );
154 return __mingw_wcsrtombs_internal( mbs, wcs, len, ps );
157 /* $RCSfile$: end of file */