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