| 1 | #include "stdio_impl.h" |
| 2 | #include "locale_impl.h" |
| 3 | #include <wchar.h> |
| 4 | #include <errno.h> |
| 5 | |
| 6 | static wint_t __fgetwc_unlocked_internal(FILE *f) |
| 7 | { |
| 8 | 	wchar_t wc; |
| 9 | 	int c; |
| 10 | 	size_t l; |
| 11 | |
| 12 | 	/* Convert character from buffer if possible */ |
| 13 | 	if (f->rpos != f->rend) { |
| 14 | 		l = mbtowc(&wc, (void *)f->rpos, f->rend - f->rpos); |
| 15 | 		if (l+1 >= 1) { |
| 16 | 			f->rpos += l + !l; /* l==0 means 1 byte, null */ |
| 17 | 			return wc; |
| 18 | 		} |
| 19 | 	} |
| 20 | |
| 21 | 	/* Convert character byte-by-byte */ |
| 22 | 	mbstate_t st = { 0 }; |
| 23 | 	unsigned char b; |
| 24 | 	int first = 1; |
| 25 | 	do { |
| 26 | 		b = c = getc_unlocked(f); |
| 27 | 		if (c < 0) { |
| 28 | 			if (!first) { |
| 29 | 				f->flags |= F_ERR; |
| 30 | 				errno = EILSEQ; |
| 31 | 			} |
| 32 | 			return WEOF; |
| 33 | 		} |
| 34 | 		l = mbrtowc(&wc, (void *)&b, 1, &st); |
| 35 | 		if (l == -1) { |
| 36 | 			if (!first) { |
| 37 | 				f->flags |= F_ERR; |
| 38 | 				ungetc(b, f); |
| 39 | 			} |
| 40 | 			return WEOF; |
| 41 | 		} |
| 42 | 		first = 0; |
| 43 | 	} while (l == -2); |
| 44 | |
| 45 | 	return wc; |
| 46 | } |
| 47 | |
| 48 | wint_t __fgetwc_unlocked(FILE *f) |
| 49 | { |
| 50 | 	locale_t *ploc = &CURRENT_LOCALE, loc = *ploc; |
| 51 | 	if (f->mode <= 0) fwide(f, 1); |
| 52 | 	*ploc = f->locale; |
| 53 | 	wchar_t wc = __fgetwc_unlocked_internal(f); |
| 54 | 	*ploc = loc; |
| 55 | 	return wc; |
| 56 | } |
| 57 | |
| 58 | wint_t fgetwc(FILE *f) |
| 59 | { |
| 60 | 	wint_t c; |
| 61 | 	FLOCK(f); |
| 62 | 	c = __fgetwc_unlocked(f); |
| 63 | 	FUNLOCK(f); |
| 64 | 	return c; |
| 65 | } |
| 66 | |
| 67 | weak_alias(__fgetwc_unlocked, fgetwc_unlocked); |
| 68 | weak_alias(__fgetwc_unlocked, getwc_unlocked); |