1 /* Copyright (C) 2004 Manuel Novoa III <mjn3@codepoet.org>
2 *
3 * GNU Library General Public License (LGPL) version 2 or later.
4 *
5 * Dedicated to Toni. See uClibc/DEDICATION.mjn3 for details.
6 */
7
8 #include "_stdio.h"
9
10
11
12 #ifdef __DO_UNLOCKED
13
munge_stream(register FILE * stream,unsigned char * buf)14 static void munge_stream(register FILE *stream, unsigned char *buf)
15 {
16 stream->__bufend = stream->__bufstart = buf;
17 __STDIO_STREAM_INIT_BUFREAD_BUFPOS(stream);
18 __STDIO_STREAM_DISABLE_GETC(stream);
19 __STDIO_STREAM_DISABLE_PUTC(stream);
20 }
21
fgetwc_unlocked(register FILE * stream)22 wint_t fgetwc_unlocked(register FILE *stream)
23 {
24 wint_t wi;
25 wchar_t wc[1];
26 int n;
27 size_t r;
28 unsigned char sbuf[1];
29
30 __STDIO_STREAM_VALIDATE(stream);
31
32 wi = WEOF; /* Prepare for failure. */
33
34 if (__STDIO_STREAM_IS_WIDE_READING(stream)
35 || !__STDIO_STREAM_TRANS_TO_READ(stream, __FLAG_WIDE)
36 ) {
37 if (stream->__modeflags & __FLAG_UNGOT) { /* Any ungetwc()s? */
38 if (((stream->__modeflags & 1) || stream->__ungot[1])) {
39 stream->__ungot_width[0] = 0; /* Application ungot... */
40 } else { /* scanf ungot */
41 stream->__ungot_width[0] = stream->__ungot_width[1];
42 }
43
44 wi = stream->__ungot[(stream->__modeflags--) & 1];
45 stream->__ungot[1] = 0;
46 goto DONE;
47 }
48
49 if (!stream->__bufstart) { /* Ugh... stream isn't buffered! */
50 /* Munge the stream temporarily to use a 1-byte buffer. */
51 munge_stream(stream, sbuf);
52 ++stream->__bufend;
53 }
54
55 if (stream->__state.__mask == 0) { /* If last was a complete char */
56 stream->__ungot_width[0] = 0; /* then reset the width. */
57 }
58
59 LOOP:
60 if ((n = __STDIO_STREAM_BUFFER_RAVAIL(stream)) == 0) {
61 goto FILL_BUFFER;
62 }
63
64 r = mbrtowc(wc, (const char*) stream->__bufpos, n, &stream->__state);
65 if (((ssize_t) r) >= 0) { /* Success... */
66 if (r == 0) { /* Nul wide char... means 0 byte for us so */
67 ++r; /* increment r and handle below as single. */
68 }
69 stream->__bufpos += r;
70 stream->__ungot_width[0] += r;
71 wi = *wc;
72 goto DONE;
73 }
74
75 if (r == ((size_t) -2)) {
76 /* Potentially valid but incomplete and no more buffered. */
77 stream->__bufpos += n; /* Update bufpos for stream. */
78 stream->__ungot_width[0] += n;
79 FILL_BUFFER:
80 if(__STDIO_FILL_READ_BUFFER(stream)) { /* Refill succeeded? */
81 goto LOOP;
82 }
83 if (!__FERROR_UNLOCKED(stream)) { /* EOF with no error. */
84 if (!stream->__state.__mask) { /* No partial wchar. */
85 goto DONE;
86 }
87 /* EOF but partially complete wchar. */
88 /* TODO: should EILSEQ be set? */
89 __set_errno(EILSEQ);
90 }
91 }
92
93 /* If we reach here, either r == ((size_t)-1) and mbrtowc set errno
94 * to EILSEQ, or r == ((size_t)-2) and stream is in an error state
95 * or at EOF with a partially complete wchar. Make sure stream's
96 * error indicator is set. */
97 stream->__modeflags |= __FLAG_ERROR;
98
99 DONE:
100 if (stream->__bufstart == sbuf) { /* Need to un-munge the stream. */
101 munge_stream(stream, NULL);
102 }
103
104 }
105
106 __STDIO_STREAM_VALIDATE(stream);
107
108 return wi;
109 }
110 libc_hidden_def(fgetwc_unlocked)
111
112 strong_alias(fgetwc_unlocked,getwc_unlocked)
113 #ifndef __UCLIBC_HAS_THREADS__
114 strong_alias(fgetwc_unlocked,fgetwc)
115 libc_hidden_def(fgetwc)
116
117 strong_alias(fgetwc_unlocked,getwc)
118 #endif
119
120 #elif defined __UCLIBC_HAS_THREADS__
121
122 wint_t fgetwc(register FILE *stream)
123 {
124 wint_t retval;
125 __STDIO_AUTO_THREADLOCK_VAR;
126
127 __STDIO_AUTO_THREADLOCK(stream);
128
129 retval = fgetwc_unlocked(stream);
130
131 __STDIO_AUTO_THREADUNLOCK(stream);
132
133 return retval;
134 }
135 libc_hidden_def(fgetwc)
136
137 strong_alias(fgetwc,getwc)
138 #endif
139