101abeacded873dd835d2115d7c9a9b0b47e75254Elliott Hughes/*	$OpenBSD: fgetln.c,v 1.13 2015/01/05 21:58:52 millert Exp $ */
21dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*-
31dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Copyright (c) 1990, 1993
41dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *	The Regents of the University of California.  All rights reserved.
51dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
61dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * This code is derived from software contributed to Berkeley by
71dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Chris Torek.
81dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
91dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Redistribution and use in source and binary forms, with or without
101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * modification, are permitted provided that the following conditions
111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * are met:
121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    documentation and/or other materials provided with the distribution.
17b2e1abda0503874a5bb097e0b55ad4f8ce211a8dElliott Hughes * 3. Neither the name of the University nor the names of its contributors
181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    may be used to endorse or promote products derived from this software
191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *    without specific prior written permission.
201dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project *
211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * SUCH DAMAGE.
321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdio.h>
351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <stdlib.h>
361dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include <string.h>
371dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#include "local.h"
381dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Expand the line buffer.  Return -1 on error.
411dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
42f1ada79a83f6ac42f5efd995bf04374005ac532bElliott Hughesstatic int
431dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project__slbexpand(FILE *fp, size_t newsize)
441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
451dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	void *p;
461dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
476b05c8e28017518fae04a3a601d0d245916561d2Elliott Hughes	if (fp->_lb._size >= newsize)
481dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		return (0);
491dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	if ((p = realloc(fp->_lb._base, newsize)) == NULL)
501dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		return (-1);
511dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	fp->_lb._base = p;
521dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	fp->_lb._size = newsize;
531dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	return (0);
541dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
551dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
561dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project/*
571dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * Get an input line.  The returned pointer often (but not always)
580133944b09d1c0a35041f7a41eb6bfb660144f4fElliott Hughes * points into a stdio buffer.  Fgetline does not alter the text of
591dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * the returned line (which is thus not a C string because it will
601dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * not necessarily end with '\0'), but does allow callers to modify
611dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project * it if they wish.  Thus, we set __SMOD in case the caller does.
621dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project */
631dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectchar *
641dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projectfgetln(FILE *fp, size_t *lenp)
651dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project{
661dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	unsigned char *p;
670133944b09d1c0a35041f7a41eb6bfb660144f4fElliott Hughes	char *ret;
681dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	size_t len;
691dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	size_t off;
701dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
71f582340a6a48588aa50da17e1620e8f91b146941Kenny Root	FLOCKFILE(fp);
720133944b09d1c0a35041f7a41eb6bfb660144f4fElliott Hughes	_SET_ORIENTATION(fp, -1);
730133944b09d1c0a35041f7a41eb6bfb660144f4fElliott Hughes
741dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/* make sure there is input */
750133944b09d1c0a35041f7a41eb6bfb660144f4fElliott Hughes	if (fp->_r <= 0 && __srefill(fp))
760133944b09d1c0a35041f7a41eb6bfb660144f4fElliott Hughes		goto error;
771dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
781dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/* look for a newline in the input */
790133944b09d1c0a35041f7a41eb6bfb660144f4fElliott Hughes	if ((p = memchr((void *)fp->_p, '\n', fp->_r)) != NULL) {
801dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		/*
811dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		 * Found one.  Flag buffer as modified to keep fseek from
821dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		 * `optimising' a backward seek, in case the user stomps on
831dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		 * the text.
841dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		 */
851dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		p++;		/* advance over it */
861dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		ret = (char *)fp->_p;
871dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		*lenp = len = p - fp->_p;
881dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		fp->_flags |= __SMOD;
891dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		fp->_r -= len;
901dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		fp->_p = p;
91f582340a6a48588aa50da17e1620e8f91b146941Kenny Root		FUNLOCKFILE(fp);
921dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		return (ret);
931dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
941dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
951dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	/*
961dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * We have to copy the current buffered data to the line buffer.
971dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * As a bonus, though, we can leave off the __SMOD.
981dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 *
991dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * OPTIMISTIC is length that we (optimistically) expect will
100b2e1abda0503874a5bb097e0b55ad4f8ce211a8dElliott Hughes	 * accommodate the `rest' of the string, on each trip through the
1011dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 * loop below.
1021dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	 */
1031dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project#define OPTIMISTIC 80
1041dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1051dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	for (len = fp->_r, off = 0;; len += fp->_r) {
1061dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		size_t diff;
1071dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1081dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		/*
1091dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		 * Make sure there is room for more bytes.  Copy data from
1101dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		 * file buffer to line buffer, refill file and look for
1111dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		 * newline.  The loop stops only when we find a newline.
1121dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		 */
1131dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		if (__slbexpand(fp, len + OPTIMISTIC))
1141dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			goto error;
1151dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		(void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p,
1161dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		    len - off);
1171dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		off = len;
1181dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		if (__srefill(fp))
1191dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			break;	/* EOF or error: return partial line */
1200133944b09d1c0a35041f7a41eb6bfb660144f4fElliott Hughes		if ((p = memchr((void *)fp->_p, '\n', fp->_r)) == NULL)
1211dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			continue;
1221dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1231dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		/* got it: finish up the line (like code above) */
1241dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		p++;
1251dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		diff = p - fp->_p;
1261dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		len += diff;
1271dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		if (__slbexpand(fp, len))
1281dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project			goto error;
1291dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		(void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p,
1301dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		    diff);
1311dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		fp->_r -= diff;
1321dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		fp->_p = p;
1331dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project		break;
1341dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	}
1351dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project	*lenp = len;
1360133944b09d1c0a35041f7a41eb6bfb660144f4fElliott Hughes	ret = (char *)fp->_lb._base;
137f582340a6a48588aa50da17e1620e8f91b146941Kenny Root	FUNLOCKFILE(fp);
1380133944b09d1c0a35041f7a41eb6bfb660144f4fElliott Hughes	return (ret);
1391dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project
1401dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Projecterror:
141f582340a6a48588aa50da17e1620e8f91b146941Kenny Root	FUNLOCKFILE(fp);
14201abeacded873dd835d2115d7c9a9b0b47e75254Elliott Hughes	*lenp = 0;
14301abeacded873dd835d2115d7c9a9b0b47e75254Elliott Hughes	return (NULL);
1441dc9e472e19acfe6dc7f41e429236e7eef7ceda1The Android Open Source Project}
145