xref: /netbsd-src/lib/libc/stdio/fgetwln.c (revision e2227050682e0c2bf7206b78af09c82bc6b75f79)
1*e2227050Schristos /*	$NetBSD: fgetwln.c,v 1.8 2016/08/27 13:15:48 christos Exp $	*/
2f432bbb6Schristos 
3f432bbb6Schristos /*-
4f432bbb6Schristos  * Copyright (c) 2002-2004 Tim J. Robbins.
5f432bbb6Schristos  * All rights reserved.
6f432bbb6Schristos  *
7f432bbb6Schristos  * Redistribution and use in source and binary forms, with or without
8f432bbb6Schristos  * modification, are permitted provided that the following conditions
9f432bbb6Schristos  * are met:
10f432bbb6Schristos  * 1. Redistributions of source code must retain the above copyright
11f432bbb6Schristos  *    notice, this list of conditions and the following disclaimer.
12f432bbb6Schristos  * 2. Redistributions in binary form must reproduce the above copyright
13f432bbb6Schristos  *    notice, this list of conditions and the following disclaimer in the
14f432bbb6Schristos  *    documentation and/or other materials provided with the distribution.
15f432bbb6Schristos  *
16f432bbb6Schristos  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17f432bbb6Schristos  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18f432bbb6Schristos  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19f432bbb6Schristos  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20f432bbb6Schristos  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21f432bbb6Schristos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22f432bbb6Schristos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23f432bbb6Schristos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24f432bbb6Schristos  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25f432bbb6Schristos  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26f432bbb6Schristos  * SUCH DAMAGE.
27f432bbb6Schristos  */
28f432bbb6Schristos 
29f432bbb6Schristos #include <sys/cdefs.h>
30f432bbb6Schristos #if defined(LIBC_SCCS) && !defined(lint)
31f432bbb6Schristos #if 0
32f432bbb6Schristos __FBSDID("$FreeBSD: src/lib/libc/stdio/fgetwln.c,v 1.2 2004/08/06 17:00:09 tjr Exp $");
33f432bbb6Schristos #else
34*e2227050Schristos __RCSID("$NetBSD: fgetwln.c,v 1.8 2016/08/27 13:15:48 christos Exp $");
35f432bbb6Schristos #endif
36f432bbb6Schristos #endif /* LIBC_SCCS and not lint */
37f432bbb6Schristos 
38f432bbb6Schristos #include "namespace.h"
3986eafd3eSroy #include <assert.h>
4086eafd3eSroy #include <errno.h>
4186eafd3eSroy #include <limits.h>
42f432bbb6Schristos #include <stdio.h>
4386eafd3eSroy #include <stdlib.h>
44f432bbb6Schristos #include <wchar.h>
45f432bbb6Schristos #include "reentrant.h"
46f432bbb6Schristos #include "local.h"
47f432bbb6Schristos 
48f432bbb6Schristos #ifdef __weak_alias
__weak_alias(fgetwln,_fgetwln)49f432bbb6Schristos __weak_alias(fgetwln,_fgetwln)
50f432bbb6Schristos #endif
51f432bbb6Schristos 
5286eafd3eSroy /*
5386eafd3eSroy  * Expand the line buffer.  Return -1 on error.
5486eafd3eSroy #ifdef notdef
5586eafd3eSroy  * The `new size' does not account for a terminating '\0',
5686eafd3eSroy  * so we add 1 here.
5786eafd3eSroy #endif
5886eafd3eSroy  */
5986eafd3eSroy static int
6086eafd3eSroy __slbexpand(FILE *fp, size_t newsize)
6186eafd3eSroy {
6286eafd3eSroy 	void *p;
6386eafd3eSroy 
6486eafd3eSroy #ifdef notdef
6586eafd3eSroy 	++newsize;
6686eafd3eSroy #endif
6786eafd3eSroy 	_DIAGASSERT(fp != NULL);
6886eafd3eSroy 
6900711901Sjoerg 	if (_EXT(fp)->_fgetstr_len >= newsize)
70526d9427Schristos 		return 0;
7100711901Sjoerg 	if ((p = realloc(_EXT(fp)->_fgetstr_buf, newsize)) == NULL)
72526d9427Schristos 		return -1;
7300711901Sjoerg 	_EXT(fp)->_fgetstr_buf = p;
7400711901Sjoerg 	_EXT(fp)->_fgetstr_len = newsize;
75526d9427Schristos 	return 0;
7686eafd3eSroy }
7786eafd3eSroy 
78f432bbb6Schristos wchar_t *
fgetwln(FILE * __restrict fp,size_t * lenp)79f432bbb6Schristos fgetwln(FILE * __restrict fp, size_t *lenp)
80f432bbb6Schristos {
81f432bbb6Schristos 	wint_t wc;
82f432bbb6Schristos 	size_t len;
83f432bbb6Schristos 
84f432bbb6Schristos 	FLOCKFILE(fp);
85f432bbb6Schristos 	_SET_ORIENTATION(fp, 1);
86f432bbb6Schristos 
87f432bbb6Schristos 	len = 0;
88f432bbb6Schristos 	while ((wc = __fgetwc_unlock(fp)) != WEOF) {
89f432bbb6Schristos #define	GROW	512
9000711901Sjoerg 		if (len * sizeof(wchar_t) >= _EXT(fp)->_fgetstr_len &&
91*e2227050Schristos 		    __slbexpand(fp, (len + GROW) * sizeof(wchar_t))) {
92*e2227050Schristos 			fp->_flags |= __SERR;
93f432bbb6Schristos 			goto error;
94*e2227050Schristos 		}
9500711901Sjoerg 		*((wchar_t *)(void *)_EXT(fp)->_fgetstr_buf + len++) = wc;
96f432bbb6Schristos 		if (wc == L'\n')
97f432bbb6Schristos 			break;
98f432bbb6Schristos 	}
99*e2227050Schristos 
100*e2227050Schristos 	/*
101*e2227050Schristos 	 * The following test assumes that fgetwc() fails when
102*e2227050Schristos 	 * feof() is already set, and that fgetwc() will never
103*e2227050Schristos 	 * set feof() in the same call where it also sets ferror()
104*e2227050Schristos 	 * or returns non-WEOF.
105*e2227050Schristos 	 * Testing ferror() would not be better because fgetwc()
106*e2227050Schristos 	 * may succeed even when ferror() is already set.
107*e2227050Schristos 	 */
108*e2227050Schristos 
109*e2227050Schristos 	if (len == 0 || (wc == WEOF && !__sfeof(fp)))
110f432bbb6Schristos 		goto error;
111f432bbb6Schristos 
112f432bbb6Schristos 	FUNLOCKFILE(fp);
113f432bbb6Schristos 	*lenp = len;
114526d9427Schristos 	return (wchar_t *)(void *)_EXT(fp)->_fgetstr_buf;
115f432bbb6Schristos 
116f432bbb6Schristos error:
117f432bbb6Schristos 	FUNLOCKFILE(fp);
118f432bbb6Schristos 	*lenp = 0;
119526d9427Schristos 	return NULL;
120f432bbb6Schristos }
121