fgetln.c revision 22993
1/*-
2 * Copyright (c) 1990, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Chris Torek.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37#if defined(LIBC_SCCS) && !defined(lint)
38#if 0
39static char sccsid[] = "@(#)fgetln.c	8.2 (Berkeley) 1/2/94";
40#endif
41static const char rcsid[] =
42		"$Id$";
43#endif /* LIBC_SCCS and not lint */
44
45#include <stdio.h>
46#include <stdlib.h>
47#include <string.h>
48#include "local.h"
49
50/*
51 * Expand the line buffer.  Return -1 on error.
52#ifdef notdef
53 * The `new size' does not account for a terminating '\0',
54 * so we add 1 here.
55#endif
56 */
57int
58__slbexpand(fp, newsize)
59	FILE *fp;
60	size_t newsize;
61{
62	void *p;
63
64#ifdef notdef
65	++newsize;
66#endif
67	if (fp->_lb._size >= newsize)
68		return (0);
69	if ((p = realloc(fp->_lb._base, newsize)) == NULL)
70		return (-1);
71	fp->_lb._base = p;
72	fp->_lb._size = newsize;
73	return (0);
74}
75
76/*
77 * Get an input line.  The returned pointer often (but not always)
78 * points into a stdio buffer.  Fgetln does not alter the text of
79 * the returned line (which is thus not a C string because it will
80 * not necessarily end with '\0'), but does allow callers to modify
81 * it if they wish.  Thus, we set __SMOD in case the caller does.
82 */
83char *
84fgetln(fp, lenp)
85	register FILE *fp;
86	size_t *lenp;
87{
88	register unsigned char *p;
89	register size_t len;
90	size_t off;
91
92	/* make sure there is input */
93	if (fp->_r <= 0 && __srefill(fp)) {
94		*lenp = 0;
95		return (NULL);
96	}
97
98	/* look for a newline in the input */
99	if ((p = memchr((void *)fp->_p, '\n', (size_t)fp->_r)) != NULL) {
100		register char *ret;
101
102		/*
103		 * Found one.  Flag buffer as modified to keep fseek from
104		 * `optimising' a backward seek, in case the user stomps on
105		 * the text.
106		 */
107		p++;		/* advance over it */
108		ret = (char *)fp->_p;
109		*lenp = len = p - fp->_p;
110		fp->_flags |= __SMOD;
111		fp->_r -= len;
112		fp->_p = p;
113		return (ret);
114	}
115
116	/*
117	 * We have to copy the current buffered data to the line buffer.
118	 * As a bonus, though, we can leave off the __SMOD.
119	 *
120	 * OPTIMISTIC is length that we (optimistically) expect will
121	 * accomodate the `rest' of the string, on each trip through the
122	 * loop below.
123	 */
124#define OPTIMISTIC 80
125
126	for (len = fp->_r, off = 0;; len += fp->_r) {
127		register size_t diff;
128
129		/*
130		 * Make sure there is room for more bytes.  Copy data from
131		 * file buffer to line buffer, refill file and look for
132		 * newline.  The loop stops only when we find a newline.
133		 */
134		if (__slbexpand(fp, len + OPTIMISTIC))
135			goto error;
136		(void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p,
137		    len - off);
138		off = len;
139		if (__srefill(fp))
140			break;	/* EOF or error: return partial line */
141		if ((p = memchr((void *)fp->_p, '\n', (size_t)fp->_r)) == NULL)
142			continue;
143
144		/* got it: finish up the line (like code above) */
145		p++;
146		diff = p - fp->_p;
147		len += diff;
148		if (__slbexpand(fp, len))
149			goto error;
150		(void)memcpy((void *)(fp->_lb._base + off), (void *)fp->_p,
151		    diff);
152		fp->_r -= diff;
153		fp->_p = p;
154		break;
155	}
156	*lenp = len;
157#ifdef notdef
158	fp->_lb._base[len] = 0;
159#endif
160	return ((char *)fp->_lb._base);
161
162error:
163	*lenp = 0;		/* ??? */
164	return (NULL);		/* ??? */
165}
166