xref: /openbsd-src/lib/libc/stdio/fgetwln.c (revision 1c50512a2b2262363e327edc19370b2d0339ca11)
1 /*	$OpenBSD: fgetwln.c,v 1.4 2016/08/27 12:08:38 schwarze Exp $	*/
2 
3 /*-
4  * Copyright (c) 2002-2004 Tim J. Robbins.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28 
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <wchar.h>
32 #include "local.h"
33 
34 /*
35  * Expand the line buffer.  Return -1 on error.
36  */
37 static int
__slbexpand(FILE * fp,size_t newsize)38 __slbexpand(FILE *fp, size_t newsize)
39 {
40 	void *p;
41 
42 	if (fp->_lb._size / sizeof(wchar_t) >= newsize)
43 		return 0;
44 	if ((p = reallocarray(fp->_lb._base, newsize, sizeof(wchar_t))) == NULL)
45 		return -1;
46 	fp->_lb._base = p;
47 	fp->_lb._size = newsize * sizeof(wchar_t);
48 	return 0;
49 }
50 
51 wchar_t *
fgetwln(FILE * __restrict fp,size_t * lenp)52 fgetwln(FILE * __restrict fp, size_t *lenp)
53 {
54 	wint_t wc;
55 	size_t len;
56 
57 	FLOCKFILE(fp);
58 	_SET_ORIENTATION(fp, 1);
59 
60 	len = 0;
61 	while ((wc = __fgetwc_unlock(fp)) != WEOF) {
62 #define	GROW	512
63 		if (len >= fp->_lb._size / sizeof(wchar_t) &&
64 		    __slbexpand(fp, len + GROW)) {
65 			fp->_flags |= __SERR;
66 			goto error;
67 		}
68 		*((wchar_t *)fp->_lb._base + len++) = wc;
69 		if (wc == L'\n')
70 			break;
71 	}
72 
73 	/*
74 	 * The following test assumes that fgetwc() fails when
75 	 * feof() is already set, and that fgetwc() will never
76 	 * set feof() in the same call where it also sets ferror()
77 	 * or returns non-WEOF.
78 	 * Testing ferror() would not be better because fgetwc()
79 	 * may succeed even when ferror() is already set.
80 	 */
81 
82 	if (len == 0 || (wc == WEOF && !__sfeof(fp)))
83 		goto error;
84 
85 	FUNLOCKFILE(fp);
86 	*lenp = len;
87 	return (wchar_t *)fp->_lb._base;
88 
89 error:
90 	FUNLOCKFILE(fp);
91 	*lenp = 0;
92 	return NULL;
93 }
94