OSDN Git Service

Correct project name references in mingwrt source files.
[mingw/mingw-org-wsl.git] / mingwrt / mingwex / wcsrtombs.c
1 /*
2  * wcsrtombs.c
3  *
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.
7  *
8  *
9  * $Id$
10  *
11  * Written by Keith Marshall <keith@users.osdn.me>
12  * Copyright (C) 2019, 2020, 2022, MinGW.OSDN Project
13  *
14  *
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:
21  *
22  * The above copyright notice, this permission notice, and the following
23  * disclaimer shall be included in all copies or substantial portions of
24  * the Software.
25  *
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.
33  *
34  */
35 #include "wcharmap.h"
36
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
40 )
41 { /* Internal implementation of the wcsrtombs() function; this will be
42    * expanded inline, within the body of the public implementation.
43    *
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.
47    */
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);
51
52   /* This wcsrtombs() implementation will not use any mbstate...
53    */
54   if( ps != NULL )
55   { /* ...unless it is provided by the caller, in which case we will,
56      * ultimately, reset it to initial state, after processing it...
57      */
58     resume.ps = *ps;
59     *ps = (mbstate_t)(0);
60     if( IS_SURROGATE_PAIR( resume.wc[0], **wcs ) )
61     { /* ...subject to the expectation that it represents deferred
62        * completion of a surrogate pair.
63        */
64       resume.wc[1] = *(*wcs)++;
65       count = __mingw_wctomb_convert( NULL, 0, resume.wc, 2 );
66     }
67   }
68
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.
72    */
73   wanted = count + __mingw_wctomb_convert( NULL, 0, *wcs, -1 );
74
75   if( mbs == NULL )
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.
80      */
81     return (errno == 0) ? errout( errno_reset, wanted - 1 ) : wanted;
82
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.
89      */
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;
93     *wcs = NULL;
94   }
95
96   else
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.
102      */
103     errno = 0;
104
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...
108      */
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.
114        */
115       mbs += __mingw_wctomb_convert( mbs, len, resume.wc, 2 );
116       len -= count;
117     }
118     while( (len >= __mingw_wctomb_convert( NULL, 0, *wcs, 1 )) && (errno == 0) )
119     {
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.
124        */
125       size_t step = __mingw_wctomb_convert( mbs, len, (*wcs)++, 1 );
126       count += step; len -= step; mbs += step;
127     }
128
129     /* Check that we didn't fall foul of any incipient encoding error;
130      * if we did, then we must bail out.
131      */
132     if( errno != 0 ) return (size_t)(-1);
133   }
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.
137    */
138   return errout( errno_reset, count );
139 }
140
141 size_t wcsrtombs( char *mbs, const wchar_t **wcs, size_t len, mbstate_t *ps )
142 {
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.
146    */
147   if( (wcs == NULL) || (*wcs == NULL) ) return errout( EINVAL, (size_t)(-1) );
148
149   /* With a valid wcs reference, store the effective codeset, and
150    * hand the conversion off to the inline expansion of the preceding
151    * implementation.
152    */
153   (void)(__mingw_wctomb_codeset_init() );
154   return __mingw_wcsrtombs_internal( mbs, wcs, len, ps );
155 }
156
157 /* $RCSfile$: end of file */