1139804Simp/*-
248391Speter * Copyright (c) 1990, 1993
348391Speter *	The Regents of the University of California.  All rights reserved.
448391Speter *
548391Speter * This code is derived from software contributed to Berkeley by
648391Speter * Chris Torek.
748391Speter *
848391Speter * Redistribution and use in source and binary forms, with or without
948391Speter * modification, are permitted provided that the following conditions
1048391Speter * are met:
1148391Speter * 1. Redistributions of source code must retain the above copyright
1248391Speter *    notice, this list of conditions and the following disclaimer.
1348391Speter * 2. Redistributions in binary form must reproduce the above copyright
1448391Speter *    notice, this list of conditions and the following disclaimer in the
1548391Speter *    documentation and/or other materials provided with the distribution.
1648391Speter * 3. Neither the name of the University nor the names of its contributors
1748391Speter *    may be used to endorse or promote products derived from this software
1848391Speter *    without specific prior written permission.
1948391Speter *
2048391Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2148391Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2248391Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2348391Speter * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
2448391Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2548391Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2648391Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27116182Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28116182Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29116182Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3048391Speter * SUCH DAMAGE.
3148391Speter */
3248391Speter
3370317Sjake#if defined(LIBC_SCCS) && !defined(lint)
3474927Sjhbstatic char sccsid[] = "@(#)fgetln.c	8.2 (Berkeley) 1/2/94";
3574927Sjhb#endif /* LIBC_SCCS and not lint */
3655722Simp#include <sys/cdefs.h>
3755539Sluoqi__FBSDID("$FreeBSD$");
3874927Sjhb
3948391Speter#include "namespace.h"
4048391Speter#include <stdio.h>
41166188Sjeff#include <stdlib.h>
42173004Sjulian#include <string.h>
43173004Sjulian#include "un-namespace.h"
4448391Speter#include "libc_private.h"
4548391Speter#include "local.h"
4648391Speter
4748391Speter/*
4848391Speter * Expand the line buffer.  Return -1 on error.
4948391Speter#ifdef notdef
5048391Speter * The `new size' does not account for a terminating '\0',
5148391Speter * so we add 1 here.
5248391Speter#endif
5348391Speter */
5448391Speterint
5548391Speter__slbexpand(FILE *fp, size_t newsize)
5648391Speter{
5748391Speter	void *p;
5848391Speter
5948391Speter#ifdef notdef
6048391Speter	++newsize;
61172836Sjulian#endif
62104354Sscottl	if (fp->_lb._size >= newsize)
6348391Speter		return (0);
6448391Speter	if ((p = realloc(fp->_lb._base, newsize)) == NULL)
6548391Speter		return (-1);
6648391Speter	fp->_lb._base = p;
6748391Speter	fp->_lb._size = newsize;
6865557Sjasone	return (0);
6948391Speter}
7065557Sjasone
7165557Sjasone/*
7265557Sjasone * Get an input line.  The returned pointer often (but not always)
7365557Sjasone * points into a stdio buffer.  Fgetln does not alter the text of
7465557Sjasone * the returned line (which is thus not a C string because it will
7565557Sjasone * not necessarily end with '\0'), but does allow callers to modify
7648391Speter * it if they wish.  Thus, we set __SMOD in case the caller does.
7748391Speter */
78172836Sjulianchar *
79104354Sscottlfgetln(FILE *fp, size_t *lenp)
8048391Speter{
8148391Speter	unsigned char *p;
8248391Speter	size_t len;
83103216Sjulian	size_t off;
8448391Speter
8548391Speter	FLOCKFILE(fp);
86114434Sdes	ORIENT(fp, -1);
87172836Sjulian	/* make sure there is input */
8865557Sjasone	if (fp->_r <= 0 && __srefill(fp)) {
8990375Speter		*lenp = 0;
90104354Sscottl		FUNLOCKFILE(fp);
9148391Speter		return (NULL);
9248391Speter	}
9348391Speter
9448391Speter	/* look for a newline in the input */
9548391Speter	if ((p = memchr((void *)fp->_p, '\n', (size_t)fp->_r)) != NULL) {
9648391Speter		char *ret;
9748391Speter
9848391Speter		/*
9971559Sjhb		 * Found one.  Flag buffer as modified to keep fseek from
100173004Sjulian		 * `optimising' a backward seek, in case the user stomps on
10171559Sjhb		 * the text.
102173004Sjulian		 */
103114983Sjhb		p++;		/* advance over it */
104114983Sjhb		ret = (char *)fp->_p;
105114983Sjhb		*lenp = len = p - fp->_p;
10671559Sjhb		fp->_flags |= __SMOD;
10748391Speter		fp->_r -= len;
10848391Speter		fp->_p = p;
10948391Speter		FUNLOCKFILE(fp);
11048391Speter		return (ret);
11148391Speter	}
112173004Sjulian
113173004Sjulian	/*
114173004Sjulian	 * We have to copy the current buffered data to the line buffer.
115173004Sjulian	 * As a bonus, though, we can leave off the __SMOD.
11648391Speter	 *
11748391Speter	 * OPTIMISTIC is length that we (optimistically) expect will
118103216Sjulian	 * accommodate the `rest' of the string, on each trip through the
119103216Sjulian	 * loop below.
12048391Speter	 */
12169657Sjhb#define OPTIMISTIC 80
12269657Sjhb
123170307Sjeff	for (len = fp->_r, off = 0;; len += fp->_r) {
124166188Sjeff		size_t diff;
125170307Sjeff
12669657Sjhb		/*
12769657Sjhb		 * Make sure there is room for more bytes.  Copy data from
12848391Speter		 * file buffer to line buffer, refill file and look for
12948391Speter		 * newline.  The loop stops only when we find a newline.
13048391Speter		 */
13148391Speter		if (__slbexpand(fp, len + OPTIMISTIC))
132172836Sjulian			goto error;
13348391Speter		(void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p,
13486293Speter		    len - off);
13586293Speter		off = len;
13670317Sjake		if (__srefill(fp))
13786293Speter			break;	/* EOF or error: return partial line */
13886293Speter		if ((p = memchr((void *)fp->_p, '\n', (size_t)fp->_r)) == NULL)
139155400Sjhb			continue;
140155400Sjhb
141155400Sjhb		/* got it: finish up the line (like code above) */
142155400Sjhb		p++;
143155400Sjhb		diff = p - fp->_p;
14474927Sjhb		len += diff;
14586292Sdillon		if (__slbexpand(fp, len))
14686292Sdillon			goto error;
14786292Sdillon		(void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p,
14874927Sjhb		    diff);
149155400Sjhb		fp->_r -= diff;
150155400Sjhb		fp->_p = p;
151155400Sjhb		break;
152155400Sjhb	}
153155400Sjhb	*lenp = len;
154155400Sjhb#ifdef notdef
155155400Sjhb	fp->_lb._base[len] = 0;
15686293Speter#endif
15748391Speter	FUNLOCKFILE(fp);
15848391Speter	return ((char *)fp->_lb._base);
15955539Sluoqi
16055539Sluoqierror:
16155539Sluoqi	*lenp = 0;		/* ??? */
16255539Sluoqi	FUNLOCKFILE(fp);
16355539Sluoqi	return (NULL);		/* ??? */
164172836Sjulian}
16555539Sluoqi