1 /*-
2 * Copyright (c) 2002-2004 Tim J. Robbins.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27 /*
28 FUNCTION
29 <<fgetws>>, <<fgetws_unlocked>>---get wide character string from a file or stream
30
31 INDEX
32 fgetws
33 INDEX
34 fgetws_unlocked
35 INDEX
36 _fgetws_r
37 INDEX
38 _fgetws_unlocked_r
39
40 SYNOPSIS
41 #include <wchar.h>
42 wchar_t *fgetws(wchar_t *__restrict <[ws]>, int <[n]>,
43 FILE *__restrict <[fp]>);
44
45 #define _GNU_SOURCE
46 #include <wchar.h>
47 wchar_t *fgetws_unlocked(wchar_t *__restrict <[ws]>, int <[n]>,
48 FILE *__restrict <[fp]>);
49
50 #include <wchar.h>
51 wchar_t *fgetws( wchar_t *<[ws]>,
52 int <[n]>, FILE *<[fp]>);
53
54 #include <wchar.h>
55 wchar_t *fgetws_unlocked( wchar_t *<[ws]>,
56 int <[n]>, FILE *<[fp]>);
57
58 DESCRIPTION
59 Reads at most <[n-1]> wide characters from <[fp]> until a newline
60 is found. The wide characters including to the newline are stored
61 in <[ws]>. The buffer is terminated with a 0.
62
63 <<fgetws_unlocked>> is a non-thread-safe version of <<fgetws>>.
64 <<fgetws_unlocked>> may only safely be used within a scope
65 protected by flockfile() (or ftrylockfile()) and funlockfile(). This
66 function may safely be used in a multi-threaded program if and only
67 if they are called while the invoking thread owns the (FILE *)
68 object, as is the case after a successful call to the flockfile() or
69 ftrylockfile() functions. If threads are disabled, then
70 <<fgetws_unlocked>> is equivalent to <<fgetws>>.
71
72 The <<_fgetws_r>> and <<_fgetws_unlocked_r>> functions are simply reentrant
73 version of the above and are passed an additional reentrancy structure
74 pointer: <[ptr]>.
75
76 RETURNS
77 <<fgetws>> returns the buffer passed to it, with the data
78 filled in. If end of file occurs with some data already
79 accumulated, the data is returned with no other indication. If
80 no data are read, NULL is returned instead.
81
82 PORTABILITY
83 <<fgetws>> is required by C99 and POSIX.1-2001.
84
85 <<fgetws_unlocked>> is a GNU extension.
86 */
87
88 #define _DEFAULT_SOURCE
89 #include <_ansi.h>
90 #include <errno.h>
91 #include <stdio.h>
92 #include <string.h>
93 #include <wchar.h>
94 #include "local.h"
95
96 #ifdef __IMPL_UNLOCKED__
97 #define _fgetws_r _fgetws_unlocked_r
98 #define fgetws fgetws_unlocked
99 #endif
100
101 wchar_t *
fgetws(wchar_t * ws,int n,FILE * fp)102 fgetws (
103 wchar_t * ws,
104 int n,
105 FILE * fp)
106 {
107 wchar_t *wsp;
108 size_t nconv;
109 const char *src;
110 unsigned char *nl;
111
112 _newlib_flockfile_start (fp);
113 ORIENT (fp, 1);
114
115 if (n <= 0)
116 {
117 errno = EINVAL;
118 goto error;
119 }
120
121 if (fp->_r <= 0 && _srefill ( fp))
122 /* EOF */
123 goto error;
124 wsp = ws;
125 do
126 {
127 src = (char *) fp->_p;
128 nl = memchr (fp->_p, '\n', fp->_r);
129 nconv = mbsnrtowcs (wsp, &src,
130 /* Read all bytes up to the next NL, or up to the
131 end of the buffer if there is no NL. */
132 nl != NULL ? (nl - fp->_p + 1) : fp->_r,
133 /* But never more than n - 1 wide chars. */
134 n - 1,
135 &fp->_mbstate);
136 if (nconv == (size_t) -1)
137 /* Conversion error */
138 goto error;
139 if (src == NULL)
140 {
141 /*
142 * We hit a null byte. Increment the character count,
143 * since mbsnrtowcs()'s return value doesn't include
144 * the terminating null, then resume conversion
145 * after the null.
146 */
147 nconv++;
148 src = memchr (fp->_p, '\0', fp->_r);
149 src++;
150 }
151 fp->_r -= (unsigned char *) src - fp->_p;
152 fp->_p = (unsigned char *) src;
153 n -= nconv;
154 wsp += nconv;
155 }
156 while (wsp[-1] != L'\n' && n > 1 && (fp->_r > 0
157 || _srefill ( fp) == 0));
158 if (wsp == ws)
159 /* EOF */
160 goto error;
161 if (!mbsinit (&fp->_mbstate))
162 /* Incomplete character */
163 goto error;
164 *wsp++ = L'\0';
165 _newlib_flockfile_exit (fp);
166 return ws;
167
168 error:
169 _newlib_flockfile_end (fp);
170 return NULL;
171 }
172