scc

simple c99 compiler
git clone git://git.simple-cc.org/scc
Log | Files | Refs | Submodules | README | 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 }