mbrtowc.c - scc - simple c99 compiler
 (HTM) git clone git://git.simple-cc.org/scc
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) Submodules
 (DIR) README
 (DIR) LICENSE
       ---
       mbrtowc.c (1519B)
       ---
            1 #include <errno.h>
            2 #include <stdlib.h>
            3 #include <string.h>
            4 #include <wchar.h>
            5 
            6 #include "../libc.h"
            7 
            8 #undef mbrtowc
            9 
           10 size_t
           11 mbrtowc(wchar_t *restrict pwc, const char *restrict s, size_t n,
           12         mbstate_t *restrict ps)
           13 {
           14         static mbstate_t state;
           15         const unsigned char *t = (const unsigned char *) s;
           16         wchar_t dummy;
           17         unsigned long wc;
           18         unsigned c, oc;
           19         int sh, max;
           20 
           21         if (!ps)
           22                 ps  = &state;
           23 
           24         if (t == NULL) {
           25                 if (ps->sh != 0)
           26                         goto return_error;
           27                 pwc = &dummy;
           28                 goto return_code_set;
           29         }
           30         if (n == 0)
           31                 return -2;
           32 
           33         oc = ps->oc;
           34         wc = ps->wc;
           35         sh = ps->sh;
           36 
           37         /* initial state? */
           38         if (sh == 0) {
           39                 /* NUL character? */
           40                 if ((c = wc = *t) == 0)
           41                         goto return_code;
           42                 t++;
           43                 n--;
           44 
           45                 /* fast track for ascii? */
           46                 if (c < 0x80)
           47                         goto return_code;
           48 
           49                 /* out of sequence multibyte? */
           50                 if ((c & 0xc0) != 0xc0)
           51                         goto return_error;
           52 
           53                 /* in sequence multibyte! */
           54                 oc = c << 1;
           55                 wc = 0;
           56                 sh = 1;
           57         }
           58 
           59         for ( ; n > 0; --n) {
           60                 if (sh > MB_CUR_MAX)
           61                         goto return_error;
           62 
           63                 c = *t++;
           64                 if ((c & 0xc0) != 0x80)
           65                         goto return_error;
           66 
           67                 wc <<= 6;
           68                 wc |= c & 0x3f;
           69                 oc <<= 1;
           70                 sh++;
           71 
           72                 if ((oc & 0x80) == 0) {
           73                         oc = (oc & 0xff) >> sh;
           74                         wc |= oc << (sh-1) * 6;
           75         
           76                         if (!_validutf8(wc, &max) || sh != max)
           77                                 goto return_error;
           78                         goto return_code_set;
           79                 }
           80         }
           81 
           82         ps->sh = sh;
           83         ps->oc = oc;
           84         ps->wc = wc;
           85         return -2;
           86 
           87 return_code_set:
           88         memset(ps, 0, sizeof(*ps));
           89 return_code:
           90         if (pwc)
           91                 *pwc = wc;
           92         return t - (unsigned char *) s;
           93 
           94 return_error:
           95         memset(ps, 0, sizeof(*ps));
           96         errno = EILSEQ;
           97         return -1;
           98 }