size_t (mbstowcs)(wchar_t *wcs, const char *s, size_t n) { /* translate multibyte string to wide char string */ int i; wchar_t *pwc; _Mbsave state = {0}; for (pwc = wcs; 0 < n; ++pwc, --n) { /* make another wide character */ i = _Mbtowc(pwc, s, MB_CUR_MAX, &state); if (i == -1) return (-1); else if (i == 0 || *pwc == 0) return (pwc - wcs); s += i; } return (pwc - wcs); }
_STD_BEGIN wint_t (fgetwc)(FILE *str) { /* get a wchar_t from wide stream */ _Lockfileatomic(str); if (str->_WRback < str->_WBack + sizeof (str->_WBack) / sizeof (wchar_t)) { /* deliver putback character */ wint_t ch = *str->_WRback++; _Unlockfileatomic(str); return (ch); } for (; ; ) { /* loop until wide char built */ int nc; size_t nbuf; size_t nback = str->_Back + sizeof (str->_Back) - str->_Rback; unsigned char *pbuf; wchar_t wc; if (0 < nback && (str->_Mode & _MWIDE) != 0) pbuf = str->_Rback, nbuf = nback; else if (str->_Next < str->_WRend || 0 < _WFrprep(str)) pbuf = str->_Next, nbuf = str->_WRend - str->_Next; else { /* nothing to read */ _Unlockfileatomic(str); return (WEOF); } switch (nc = _Mbtowc(&wc, (const char *)pbuf, nbuf, &str->_Wstate)) { /* check completion code */ case -2: /* not done yet */ if (sizeof (str->_Back) <= nbuf) nback = 0; /* more chars won't help, signal failure */ else if (nback == 0) { /* set up buffer in str->_Back area */ str->_Rback = str->_Back + sizeof (str->_Back) - nbuf; memcpy(str->_Rback, str->_Next, nbuf); str->_Next += nbuf; nback = nbuf; } if (nback == 0) ; /* report failure */ else if (0 < _WFrprep(str)) { /* add chars to _Back buffer and retry */ nbuf = str->_WRend - str->_Next; if (sizeof (str->_Back) - nback < nbuf) nbuf = sizeof (str->_Back) - nback; pbuf = ((str->_Back + sizeof (str->_Back)) - nbuf) - nback; memmove(pbuf, str->_Rback, nback); memcpy(pbuf + nback, str->_Next, nbuf); str->_Rback = pbuf; str->_Next += nbuf; break; } /* fall through */ case -1: /* bad multibyte character */ str->_Mode |= _MERR; _Unlockfileatomic(str); return (WEOF); case 0: /* may be null character */ if (wc == L'\0') nc = strlen((const char *)pbuf) + 1; /* fall through */ default: /* got a wide character */ if (nc == -3) nc = 0; /* generated a wide character from state info */ if (0 < nback) str->_Rback += nc; else str->_Next += nc; _Unlockfileatomic(str); return (wc); } } }
int _Scanf(int (*pfn)(void *, int), void *arg, const char *fmt, va_list ap) { /* read formatted */ int nconv = 0; _Sft x; x.pfn = pfn; x.arg = arg; x.ap = ap; x.nchar = 0; for (x.s = fmt; ; ++x.s) { /* parse format string */ int ch; { /* match any literal or white-space */ int n; wchar_t wc; _Mbsave state = {0}; while (0 < (n = _Mbtowc(&wc, x.s, MB_CUR_MAX, &state))) { /* check type of multibyte char */ x.s += n; if (wc == '%') break; else if (wc <= UCHAR_MAX && isspace(wc)) { /* match any white-space */ while (isspace(*x.s)) ++x.s; while (isspace(ch = GET(&x))) ; UNGETN(&x, ch); } else /* match literal text */ for (x.s -= n; 0 <= --n; ) if ((ch = GET(&x)) != *x.s++) { /* bad match */ UNGETN(&x, ch); return (nconv); } } if (*x.s == '\0') return (nconv); } { /* process a conversion specifier */ int code; x.noconv = *x.s == '*' ? *x.s++ : '\0'; for (x.width = 0; isdigit(*x.s); ++x.s) if (x.width < _WMAX) x.width = x.width * 10 + *x.s - '0'; x.qual = strchr("hlL", *x.s) ? *x.s++ : '\0'; if (!strchr("cn[", *x.s)) { /* match leading white-space */ while (isspace(ch = GET(&x))) ; UNGETN(&x, ch); } if ((code = _Getfld(&x)) <= 0) return (nconv == 0 ? code : nconv); if (x.stored) ++nconv; } } }
_STD_BEGIN #define NSTACK 3 /* depth of format nesting stack */ size_t _Wcsftime(wchar_t *buf, size_t bufsize, const char *fmt, size_t len, const struct tm *t) { /* format and widen time information */ const char *fmtsav[NSTACK] = { NULL }; size_t lensav[NSTACK] = { 0 }; size_t nstack = 0; wchar_t *ibuf = buf; _Mbstinit(mbst); while (0 < len || 0 < nstack) { /* parse format string */ int n; wchar_t wc = L'\0'; if (len == 0) fmt = fmtsav[--nstack], len = lensav[nstack]; if ((n = _Mbtowc(&wc, fmt, len, &mbst)) <= 0) n = *fmt == '\0' ? 0 : 1; /* bad parse, eat one char */ fmt += n, len -= n; if (wc == L'\0') ; /* discard any trailer */ else if (bufsize == 0) return (0); /* not enough room */ else if (wc != L'%' || len == 0) *buf++ = wc, --bufsize; else { /* do the conversion */ char ac[20]; char qual = (char)(*fmt == 'E' || *fmt == 'O' ? *fmt++ : '\0'); int m; const char *p; p = _Gentime(t, _TLS_DATA_PTR(_Times), qual, *fmt, &m, ac); if (qual != '\0') --len; ++fmt, --len; if (0 < m) { /* parse conversion string */ _Mbstinit(mbst2); for (; 0 < m; p += n, m -= n) if ((n = _Mbtowc(&wc, p, m, &mbst2)) <= 0) break; else if (bufsize == 0) return (0); else *buf++ = wc, --bufsize; } else if (len == 0 || NSTACK <= nstack) fmt = p, len = -m; /* tail recursion or stack full */ else { /* add leftover format to stack */ fmtsav[nstack] = fmt, fmt = p; lensav[nstack++] = len, len = -m; } } } return (buf - ibuf); }
int (mblen)(const char *s, size_t n) { /* determine length of next multibyte code */ return (_Mbtowc(NULL, s, n, &_Mbxlen)); }