]> pd.if.org Git - pdclib/blob - functions/uchar/c16rtomb.c
dos2unix
[pdclib] / functions / uchar / c16rtomb.c
1 /* c16rtomb( char *, char16_t, mbstate_t * )
2
3    This file is part of the Public Domain C Library (PDCLib).
4    Permission is granted to use, modify, and / or redistribute at will.
5 */
6
7 #ifndef REGTEST
8 #include <uchar.h>
9 #include <errno.h>
10 #include <stdint.h>
11 #include <assert.h>
12 #include <stdlib.h>
13 #include "_PDCLIB_encoding.h"
14 #include "_PDCLIB_locale.h"
15
16 size_t c16rtomb_l(
17     char        *restrict   s, 
18     char16_t                c16,
19     mbstate_t   *restrict   ps,
20     locale_t     restrict   l
21 )
22 {
23     const char16_t *restrict psrc = &c16;
24     char buf[s ? 0 : MB_CUR_MAX];
25     s =      s ? s : buf;
26
27     if(!l->_Codec->__c16stombs) {
28         // Codec doesn't support direct conversion - translate via UCS-4
29         if(ps->_Surrogate == 0) {
30             // No pending surrogate
31             if((c16 & 0xF800) == 0xD800) {
32                 // Surrogate range
33                 if((c16 & 0x0400) == 0) {
34                     // 0xD800 -> 0xDBFF leading surrogate
35                     ps->_Surrogate = c16;
36
37                     // Need more data
38                     // Return 0 - we haven't output anything yet
39
40                     /* STD: ISO/IEC 9899:2011 is very implcifit about this being
41                      *      the correct return value. N1040, from which the 
42                      *      function was adopted, is explicit about 0 being a 
43                      *      valid return.
44                      */
45                     return (size_t) 0;
46                 } else {
47                     // 0xDC00 -> 0xDFFF trailing surrogate
48                     errno = EILSEQ;
49                     return (size_t) -1;
50                 }
51             } else {
52                 // BMP range - UTF16 == UCS-4, pass through to c32rtomb_l
53                 return c32rtomb_l(s, c16, ps, l);
54             }
55         } else {
56             // We have a stored surrogate
57             if((c16 & 0xFC00) == 0xDC00) {
58                 // Trailing surrogate
59                 char32_t c32 = (ps->_Surrogate & 0x3FF) << 10 | (c16 & 0x3FF);
60                 ps->_Surrogate = 0;
61                 return c32rtomb_l(s, c32, ps, l);
62             } else {
63                 // Not a trailing surrogate - encoding error
64                 errno = EILSEQ;
65                 return (size_t) -1;
66             }
67
68         }
69     } else {
70         // Codec supports direct conversion
71         size_t srcsz  = 1;
72         size_t dstsz  = MB_CUR_MAX;
73         size_t dstrem = dstsz;
74
75         if(l->_Codec->__c16stombs(&s, &dstrem, &psrc, &srcsz, ps)) {
76             // Successful conversion
77             return dstsz - dstrem;
78         } else {
79             errno = EILSEQ;
80             return (size_t) -1;
81         }
82     }
83 }
84
85 size_t c16rtomb(
86     char        *restrict   s, 
87     char16_t                c16,
88     mbstate_t   *restrict   ps
89 )
90 {
91     return c16rtomb_l(s, c16, ps, _PDCLIB_threadlocale());
92 }
93
94 #endif
95
96 #ifdef TEST
97 #include "_PDCLIB_test.h"
98
99 int main( void )
100 {
101     TESTCASE( NO_TESTDRIVER );
102     return TEST_RESULTS;
103 }
104 #endif