| 1 | #include <wchar.h> |
| 2 | |
| 3 | size_t mbsnrtowcs(wchar_t *restrict wcs, const char **restrict src, size_t n, size_t wn, mbstate_t *restrict st) |
| 4 | { |
| 5 | 	size_t l, cnt=0, n2; |
| 6 | 	wchar_t *ws, wbuf[256]; |
| 7 | 	const char *s = *src; |
| 8 | 	const char *tmp_s; |
| 9 | |
| 10 | 	if (!wcs) ws = wbuf, wn = sizeof wbuf / sizeof *wbuf; |
| 11 | 	else ws = wcs; |
| 12 | |
| 13 | 	/* making sure output buffer size is at most n/4 will ensure |
| 14 | 	 * that mbsrtowcs never reads more than n input bytes. thus |
| 15 | 	 * we can use mbsrtowcs as long as it's practical.. */ |
| 16 | |
| 17 | 	while ( s && wn && ( (n2=n/4)>=wn || n2>32 ) ) { |
| 18 | 		if (n2>=wn) n2=wn; |
| 19 | 		tmp_s = s; |
| 20 | 		l = mbsrtowcs(ws, &s, n2, st); |
| 21 | 		if (!(l+1)) { |
| 22 | 			cnt = l; |
| 23 | 			wn = 0; |
| 24 | 			break; |
| 25 | 		} |
| 26 | 		if (ws != wbuf) { |
| 27 | 			ws += l; |
| 28 | 			wn -= l; |
| 29 | 		} |
| 30 | 		n = s ? n - (s - tmp_s) : 0; |
| 31 | 		cnt += l; |
| 32 | 	} |
| 33 | 	if (s) while (wn && n) { |
| 34 | 		l = mbrtowc(ws, s, n, st); |
| 35 | 		if (l+2<=2) { |
| 36 | 			if (!(l+1)) { |
| 37 | 				cnt = l; |
| 38 | 				break; |
| 39 | 			} |
| 40 | 			if (!l) { |
| 41 | 				s = 0; |
| 42 | 				break; |
| 43 | 			} |
| 44 | 			/* have to roll back partial character */ |
| 45 | 			*(unsigned *)st = 0; |
| 46 | 			break; |
| 47 | 		} |
| 48 | 		s += l; n -= l; |
| 49 | 		/* safe - this loop runs fewer than sizeof(wbuf)/8 times */ |
| 50 | 		ws++; wn--; |
| 51 | 		cnt++; |
| 52 | 	} |
| 53 | 	if (wcs) *src = s; |
| 54 | 	return cnt; |
| 55 | } |