| /* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org> |
| * |
| * GNU Library General Public License (LGPL) version 2 or later. |
| * |
| * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details. |
| */ |
| |
| #include "_stdio.h" |
| |
| |
| |
| #ifdef __DO_UNLOCKED |
| |
| static void munge_stream(register FILE *stream, unsigned char *buf) |
| { |
| stream->__bufend = stream->__bufstart = buf; |
| __STDIO_STREAM_INIT_BUFREAD_BUFPOS(stream); |
| __STDIO_STREAM_DISABLE_GETC(stream); |
| __STDIO_STREAM_DISABLE_PUTC(stream); |
| } |
| |
| wint_t fgetwc_unlocked(register FILE *stream) |
| { |
| wint_t wi; |
| wchar_t wc[1]; |
| int n; |
| size_t r; |
| unsigned char sbuf[1]; |
| |
| __STDIO_STREAM_VALIDATE(stream); |
| |
| wi = WEOF; /* Prepare for failure. */ |
| |
| if (__STDIO_STREAM_IS_WIDE_READING(stream) |
| || !__STDIO_STREAM_TRANS_TO_READ(stream, __FLAG_WIDE) |
| ) { |
| if (stream->__modeflags & __FLAG_UNGOT) { /* Any ungetwc()s? */ |
| if (((stream->__modeflags & 1) || stream->__ungot[1])) { |
| stream->__ungot_width[0] = 0; /* Application ungot... */ |
| } else { /* scanf ungot */ |
| stream->__ungot_width[0] = stream->__ungot_width[1]; |
| } |
| |
| wi = stream->__ungot[(stream->__modeflags--) & 1]; |
| stream->__ungot[1] = 0; |
| goto DONE; |
| } |
| |
| if (!stream->__bufstart) { /* Ugh... stream isn't buffered! */ |
| /* Munge the stream temporarily to use a 1-byte buffer. */ |
| munge_stream(stream, sbuf); |
| ++stream->__bufend; |
| } |
| |
| if (stream->__state.__mask == 0) { /* If last was a complete char */ |
| stream->__ungot_width[0] = 0; /* then reset the width. */ |
| } |
| |
| LOOP: |
| if ((n = __STDIO_STREAM_BUFFER_RAVAIL(stream)) == 0) { |
| goto FILL_BUFFER; |
| } |
| |
| r = mbrtowc(wc, (const char*) stream->__bufpos, n, &stream->__state); |
| if (((ssize_t) r) >= 0) { /* Success... */ |
| if (r == 0) { /* Nul wide char... means 0 byte for us so */ |
| ++r; /* increment r and handle below as single. */ |
| } |
| stream->__bufpos += r; |
| stream->__ungot_width[0] += r; |
| wi = *wc; |
| goto DONE; |
| } |
| |
| if (r == ((size_t) -2)) { |
| /* Potentially valid but incomplete and no more buffered. */ |
| stream->__bufpos += n; /* Update bufpos for stream. */ |
| stream->__ungot_width[0] += n; |
| FILL_BUFFER: |
| if(__STDIO_FILL_READ_BUFFER(stream)) { /* Refill succeeded? */ |
| goto LOOP; |
| } |
| if (!__FERROR_UNLOCKED(stream)) { /* EOF with no error. */ |
| if (!stream->__state.__mask) { /* No partial wchar. */ |
| goto DONE; |
| } |
| /* EOF but partially complete wchar. */ |
| /* TODO: should EILSEQ be set? */ |
| __set_errno(EILSEQ); |
| } |
| } |
| |
| /* If we reach here, either r == ((size_t)-1) and mbrtowc set errno |
| * to EILSEQ, or r == ((size_t)-2) and stream is in an error state |
| * or at EOF with a partially complete wchar. Make sure stream's |
| * error indicator is set. */ |
| stream->__modeflags |= __FLAG_ERROR; |
| |
| DONE: |
| if (stream->__bufstart == sbuf) { /* Need to un-munge the stream. */ |
| munge_stream(stream, NULL); |
| } |
| |
| } |
| |
| __STDIO_STREAM_VALIDATE(stream); |
| |
| return wi; |
| } |
| libc_hidden_def(fgetwc_unlocked) |
| |
| strong_alias(fgetwc_unlocked,getwc_unlocked) |
| #ifndef __UCLIBC_HAS_THREADS__ |
| strong_alias(fgetwc_unlocked,fgetwc) |
| libc_hidden_def(fgetwc) |
| |
| strong_alias(fgetwc_unlocked,getwc) |
| #endif |
| |
| #elif defined __UCLIBC_HAS_THREADS__ |
| |
| wint_t fgetwc(register FILE *stream) |
| { |
| wint_t retval; |
| __STDIO_AUTO_THREADLOCK_VAR; |
| |
| __STDIO_AUTO_THREADLOCK(stream); |
| |
| retval = fgetwc_unlocked(stream); |
| |
| __STDIO_AUTO_THREADUNLOCK(stream); |
| |
| return retval; |
| } |
| libc_hidden_def(fgetwc) |
| |
| strong_alias(fgetwc,getwc) |
| #endif |