1#include <wchar.h>
2
3size_t mbsnrtowcs(wchar_t* restrict wcs, const char** restrict src, size_t n, size_t wn, mbstate_t* restrict st) {
4    size_t l, cnt = 0, n2;
5    wchar_t *ws, wbuf[256];
6    const char* s = *src;
7
8    if (!wcs)
9        ws = wbuf, wn = sizeof wbuf / sizeof *wbuf;
10    else
11        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)
19            n2 = wn;
20        n -= n2;
21        l = mbsrtowcs(ws, &s, n2, st);
22        if (!(l + 1)) {
23            cnt = l;
24            wn = 0;
25            break;
26        }
27        if (ws != wbuf) {
28            ws += l;
29            wn -= l;
30        }
31        cnt += l;
32    }
33    if (s)
34        while (wn && n) {
35            l = mbrtowc(ws, s, n, st);
36            if (l + 2 <= 2) {
37                if (!(l + 1)) {
38                    cnt = l;
39                    break;
40                }
41                if (!l) {
42                    s = 0;
43                    break;
44                }
45                /* have to roll back partial character */
46                *(unsigned*)st = 0;
47                break;
48            }
49            s += l;
50            n -= l;
51            /* safe - this loop runs fewer than sizeof(wbuf)/8 times */
52            ws++;
53            wn--;
54            cnt++;
55        }
56    if (wcs)
57        *src = s;
58    return cnt;
59}
60