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