OSDN Git Service

Discontinue use of Microsoft's MBCS/wide character converters.
[mingw/mingw-org-wsl.git] / mingwrt / mingwex / wcrtomb.c
1 /*
2  * wcrtomb.c
3  *
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.
8  *
9  *
10  * $Id$
11  *
12  * Written by Keith Marshall <keith@users.osdn.me>
13  * Copyright (C) 2019, 2020, MinGW.org Project
14  *
15  *
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:
22  *
23  * The above copyright notice, this permission notice, and the following
24  * disclaimer shall be included in all copies or substantial portions of
25  * the Software.
26  *
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.
34  *
35  */
36 #include "wcharmap.h"
37
38 static __mb_inline__ size_t __wcrtomb_internal
39 ( char *restrict mb, wchar_t wc, mbstate_t *ps )
40 {
41   /* Internal implementation of the wcrtomb() function; this is
42    * expanded inline, within the public implementation.
43    */
44   if( *ps != (mbstate_t)(0) )
45   {
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.
51      */
52     if( IS_HIGH_SURROGATE( *ps ) && IS_LOW_SURROGATE( wc ) )
53     {
54       /* Reassemble the surrogate pair, in a local buffer, and
55        * return its conversion, having reset the restart state.
56        */
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 );
59     }
60     else
61     { /* We expected a low surrogate, but didn't get one; reset
62        * the restart state, and abort this conversion.
63        */
64       *ps = (mbstate_t)(0); return errout( EILSEQ, (size_t)(-1) );
65     }
66   }
67   /* When mb is a NULL pointer, ISO-C99 decrees that the call shall
68    * be interpreted as the equivalent of:
69    *
70    *   wcrtomb( internal_buffer, L'\0', ps );
71    *
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).
78    */
79   if( mb == NULL ) return (size_t)(1);
80
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.
86    */
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.
94      */
95     *ps = (mbstate_t)(wc); return (size_t)(0);
96   }
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.
101      */
102     return errout( EILSEQ, (size_t)(-1) );
103
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.
107    */
108   return __mingw_wctomb_convert( mb, __mingw_wctomb_cur_max(), &wc, 1 );
109 }
110
111 size_t wcrtomb( char *restrict mb, wchar_t wc, mbstate_t *restrict ps )
112 {
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.
116    */
117   (void)(__mingw_wctomb_cur_max_init( __mingw_wctomb_codeset_init() ));
118   return __wcrtomb_internal( mb, wc, __mbrtowc_state( ps ) );
119 }
120
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.
124  */
125 size_t __msvcrt_wcrtomb( char *restrict, wchar_t, mbstate_t *restrict )
126 __attribute__((__weak__,__alias__("wcrtomb")));
127
128 size_t __mingw_wcrtomb( char *restrict, wchar_t, mbstate_t *restrict )
129 __attribute__((__weak__,__alias__("wcrtomb")));
130
131 /* $RCSfile$: end of file */