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