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 if (ORIENT (fp, 1) != 1)
114 goto error;
115
116 if (n <= 0)
117 {
118 errno = EINVAL;
119 goto error;
120 }
121
122 if (fp->_r <= 0 && _srefill ( fp))
123 /* EOF */
124 goto error;
125 wsp = ws;
126 do
127 {
128 src = (char *) fp->_p;
129 nl = memchr (fp->_p, '\n', fp->_r);
130 nconv = mbsnrtowcs (wsp, &src,
131 /* Read all bytes up to the next NL, or up to the
132 end of the buffer if there is no NL. */
133 nl != NULL ? (nl - fp->_p + 1) : fp->_r,
134 /* But never more than n - 1 wide chars. */
135 n - 1,
136 &fp->_mbstate);
137 if (nconv == (size_t) -1)
138 /* Conversion error */
139 goto error;
140 if (src == NULL)
141 {
142 /*
143 * We hit a null byte. Increment the character count,
144 * since mbsnrtowcs()'s return value doesn't include
145 * the terminating null, then resume conversion
146 * after the null.
147 */
148 nconv++;
149 src = memchr (fp->_p, '\0', fp->_r);
150 src++;
151 }
152 fp->_r -= (unsigned char *) src - fp->_p;
153 fp->_p = (unsigned char *) src;
154 n -= nconv;
155 wsp += nconv;
156 }
157 while (wsp[-1] != L'\n' && n > 1 && (fp->_r > 0
158 || _srefill ( fp) == 0));
159 if (wsp == ws)
160 /* EOF */
161 goto error;
162 if (!mbsinit (&fp->_mbstate))
163 /* Incomplete character */
164 goto error;
165 *wsp++ = L'\0';
166 _newlib_flockfile_exit (fp);
167 return ws;
168
169 error:
170 _newlib_flockfile_end (fp);
171 return NULL;
172 }
173