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